React

1.React

React 构建用户界面的JavaScript库,主要用于构建UI界面。
特点

  1. 声明式的设计
  2. 高效,采用虚拟DOM来实现DOM的渲染,最大限制的减少DOM的操作。
  3. 灵活,跟其他库灵活搭配使用
  4. JSX,俗称JS里面写HTML,JavaScript语法的扩展
  5. 组件化、模块化。代码容易复用,2016年之前大型项目非常喜欢react
  6. 单向数据流。没有实现数据的双向绑定。数据 =》视图=》事件=》数据

创建项目

  1. 通过script引入使用,仅用于学习调试使用
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  1. 通过react的脚手架,创建项目进行开发,部署。
  • 安装脚手架 Create React App
npm install -g create-react-app
  • 创建项目
create-react-app 项目名称

2. React元素渲染

JSX元素对象,或者组件对象,必须只有1个根元素(根节点)
React JSX
优点:

  1. JSX执行更快,编译为JavaScript代码时进行优化
  2. 类型更安全,编译过程如果出错就不能编译,及时发现错误
  3. JSX编写模板更加简单快捷(不要给VUE比)

注意:

  1. JSX必须要有根节点
  2. 正常的普通HTML元素要小写,如果时大写,默认为是组件

3.JSX表达式

html的样式类名要写className 因为class在js中是关键字

  1. 由HTML元素构成
  2. 中间如果需要插入变量用{}
  3. {}中间可以使用表达式
  4. {}中间表达式中可以使用JSX对象
  5. 属性和html内容一样都是用{}来插入内容

4.JSX_style样式

const exampleStyle={background:"skyblue",borderBottom:"1px solid red"};
const element =(<div><h1 style={exampleStyle}>hello</h1></div>)

const element =(<div><h1 style={'abc'+classStr}>hello</h1></div>)

let classStr2 = ['abc2','redBg2'].join(" ");
let element2 = (<div><h1 className={classStr2}>helloworld</h1></div>)
  1. class中,不可以存在多个class属性
    <div class=‘abc’ class={‘acitive’}>错误演示
  2. style样式中,如果存在多个单词的属性组合,第二个单词开始,首字母大写(也可以双引号引起来)
  3. 多个类共存的操作
  4. 注释 必须在{}里面写 {/* 这里是注释 */}

5.React组件

  1. 函数式组件
function Childcom(props){
	let title = <h2>我是副标题</h2>
	return(
		<div>
			<h1>函数式组件</h1>
			{title}
		</div>
	)
 }
  1. 类组件
class HelloWorld extends React.Component{
	console.log(this.props);
	render(){
		return(
		<div>
			<h1>类组件</h1>
		</div>
		)
	}
}

函数式组件与类组件的区别和使用,函数式比较简单,一般用于静态没有交互事件
内容的组件页面。类组件,一般又称为动态组件,那么一般会有交互或者数据修改的操作。

  1. 函数式组件
  2. 类组件
  3. 复合组件:组件中又有其他的组件,复合组件中既可以有类组件又可以有函数组件。

6.React State 相当于vue的data,但是使用方式不同

class Clock extends React.Component{
  constructor(props){
	super(props);
	// 状态(数据)--》view
	// 构造函数初始化数据,将需要改变的数据初始化到state中
	this.state = {
	  time:new Date().toLocaleTimeString()
	}
	// console.log(this.state);
  }
  render(){
	// console.log("这是渲染函数");
	// this.state.time = new Date().toLocaleTimeString();
	return(
	  <div>
		<h1>当前时间:{this.state.time}</h1>
	  </div>
	)
  }
	  // 生命周期函数 组件渲染完成时的函数
	  componentDidMount(){
		setInterval(()=>{
		  // console.log(this.state.time);
		  // 切勿直接修改state数据,直接state重新渲染内容,需要使用setState
		  // this.state.time = new Date().toLocaleTimeString(); 错误的方式
		  // 通过this.setState修改完数据后,并不会立即修改DOM里面的内容,react会在
		  // 这个函数内容所有设置状态改变后,统一对比虚拟DOM对象,然后再统一修改,提升性能
		  // 小程序也是借鉴REACT状态管理操作
		  this.setState({
			time:new Date().toLocaleTimeString()
		  })
		},1000)
	  }
	}
	  ReactDOM.render(
		<Clock/>,
		document.getElementById('root')
	  )

7.React父传子数据传递

  • props 父传递给子组件数据,单向流动,不能子传递给父 props的传递,可以是任意的类型。

  • props可以设置默认值
    HelloMessage.defaultProps = {name:“老陈”,msg:“helloworld”}

注意: props可以传递函数,props可以传递父元素的函数,就可以去修改
父元素的state,从而达到传递数据给父元素。


// 在父元素中使用state去控制子元素props的从而达到父元素数据传递给子元素
class ParentCom extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      isActive: true
    }
    this.changeShow = this.changeShow.bind(this);
  }

  changeShow(){
    this.setState({
      isActive: !this.state.isActive
    })
  }

  render(){
    return(
      <div>
        <button onClick={this.changeShow}>控制子元素显示</button>
        <ChildCom isActive={this.state.isActive} />
      </div>
    )
  }
}


class ChildCom extends React.Component{
  constructor(props){
    super(props)
  }

  render(){
    let strClass = null;
    if(this.props.isActive){
      strClass = 'active'
    }else{
      strClass = ''
    }
    return(
      <div className={"content"+ strClass}>
        <h1>我是子元素</h1>
      </div>
    )
  }
}

ReactDOM.render(
  <ParentCom />,
  document.getElementById("root")
)

8.react数据传递子传父

调用父元素的函数从而操作父元素的数据,从而实现数据从子元素传递至父元素

// 子传父
class ParentCom extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      childData: null
    }
  }

  render(){
    return(
      <div>
        <h1>子元素传递给父元素的数据:{this.state.childData}</h1>
        <ChildCom setChildData = {this.setChildData}/>
      </div>
    )
  }
  setChildData=(data)=>{
    this.setState({
      childData: data
    })
  }
}

class ChildCom extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      msg:"Hello world"
    }
  }

  render(){
    return(
      <div>
        <button onClick={this.sendData}>传递helloworld给父元素</button>
        <button onClick={()=>{this.props.setChildData('直接调用props的函数')}}>传递helloworld给父元素</button>
      </div>
    )
  }

  sendData=()=>{
    // console.log(this.state.msg);
    console.log(this.props.setChildData);
    // 将子元素传递给到父元素,实际就说调用父元素传递进来的父元素函数
    this.props.setChildData(this.state.msg);
  }
}

ReactDOM.render(
  <ParentCom/>,
  document.getElementById('root')
)

9.React事件

特点:

  1. react事件,绑定事件的命名,驼峰命名法。
  2. {},传入一个函数,而不是字符串

事件对象:React返回的事件对象是代理的原生的事件对象,如果想要查看事件对象的具体值,必须直接输出事件对象的属性。

注意:

  • 原生,阻止默认行为时,可以直接返回return false
  • 在react中,阻止默认必须使用e.preventDefault()

react事件传参

class ParentCom extends React.Component{
  constructor(props){
    super(props);
  }

  parentEvent = (e)=>{
    console.log(e);
    e.preventDefault();
  }

  parentEvent1 = (msg,e)=>{
    console.log(msg);
    console.log(e);
  }

  render(){
    return(
      <div>
        <form action='http://www.baidu.com'>
          <div className='child'>
            <h1>hello world</h1>
            <button  onClick={this.parentEvent}>提交</button>
          </div>
        </form>
        {/* <button  onClick={this.parentEvent1('134')}>提交1</button> */}
        {/*使用es6箭头函数传递多个参数*/}
        <button  onClick={(e)=>{this.parentEvent1('fdsfsd',e)}}>提交1</button>
        {/*不使用es6箭头函数传递多个参数的方式*/}
        <button  onClick={function(e){this.parentEvent1('dsfasf',e)}.bind(this)}>提交1</button>
      </div>
    )
  }
}

ReactDOM.render(
  <ParentCom/>,
  document.getElementById('root')
)

10.React条件渲染

React中条件渲染即和Javascript中,条件运算,如if…else… 三元运算符等。

  1. 直接通过条件运算返回要渲染的JSX对象
function UserGreet(props){
  return (<h1>欢迎登录</h1>)
}

function UserLogin(props){
  return(<h1>请先登录</h1>)
}

class ParentCom extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      isLogin:false
    }
  }
  render(){
    if(this.state.isLogin){
      return (<UserGreet/>)
    }else{
      return (<UserLogin/>)
    }
  }
}

ReactDOM.render(
  <ParentCom/>,
  document.getElementById('root')
)
  1. 通过条件运算符得出JSX对象,再将JSX对象渲染到模板中
function UserGreet(props){
  return (<h1>欢迎登录</h1>)
}

function UserLogin(props){
  return(<h1>请先登录</h1>)
}

class ParentCom extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      isLogin:false
    }
  }
  render(){
    let element = null;
    if(this.state.isLogin){
      element = <UserGreet/>
    }else{
      element = <UserLogin/>
    }
    return(
      <div>
        <h1>这是头部</h1>
        {element}
         <h1>这是三元运算符的操作</h1>
        {this.state.isLogin ? <UserGreet/>:<UserLogin/>}
        <h1>这是尾部</h1>
      </div>
    )
  }
}

ReactDOM.render(
  <ParentCom/>,
  document.getElementById('root')
)

11.React列表渲染

将列表内容拼装成数组放置到模板当中。将数据拼装成数组的JSX对象

class Welcome extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      list:[
        {
          title:'第一节 React事件',
          content:"事件内容"
        },
        {
          title:'第二节 React数据传递',
          content:"数据传递内容"
        },
        {
          title:'第三节 条件渲染',
          content:"条件渲染内容"
        }
      ]
    }
  }
  render(){
    let listArr = [];
    for(let i=0;i<this.state.list.length;i++){
      let item = (
        <li>
          <h3>{this.state.list[i].title}</h3>
          <p>{this.state.list[i].content}</p>
        </li>
      )
      listArr.push(item);
    }
    return(
      <div>
        <h1>今天课程内容</h1>
        <ul>
          {listArr}
        </ul>
      </div>
    )
  }
}

ReactDOM.render(
  <Welcome/>,
  document.getElementById('root')
)

改进
使用数组的map方法,对每一项数据按照JSX的形式进行加工,最终得到1个每一项都是JSX对象的数组,再将数组渲染到模板中。
key值需要放置到每一项中

function ListItem(props){
  return(
    <li>
      <h3>{props.index+1}:{props.data.title}</h3>
      <p>{props.data.content}</p>
    </li>
  )
}
class ListItem2 extends React.Component{
  constructor(props){
    super(props)
  }
  clickEvent = (index,title,event)=>{
    alert(index+'-'+title);
  }
  render(){
    return(
      <li onClick={(e)=>{this.clickEvent(this.props.index,this.props.data.title,e)}}>
        <h3>{this.props.index+1}:{this.props.data.title}</h3>
        <p>{this.props.data.content}</p>
      </li>
    )
  }
}

class Welcome extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      list:[
        {
          title:'第一节 React事件',
          content:"事件内容"
        },
        {
          title:'第二节 React数据传递',
          content:"数据传递内容"
        },
        {
          title:'第三节 条件渲染',
          content:"条件渲染内容"
        }
      ]
    }
  }
  clickFn = (index,title,event)=>{
    alert(index+'-'+title);
  }
  render(){
    let listArr = this.state.list.map((item,index)=>{
      return(
        // <ListItem key={index} data={item} index={index}/>
        <ListItem2 key={index} data={item} index={index}/>
      )
    })
    return(
      <div>
        <h1>今天课程内容</h1>
        <ul>
          {listArr}
        </ul>
        <h1>复杂没有用组件完成列表</h1>
        {
          this.state.list.map((item,index)=>{
            return(
              <ul>
                <li key={index} onClick={(e)=>{this.clickFn(index,item.title,e)}}>
                  <h3>{index+1}:{item.title}</h3>
                  <p>{item.content}</p>
                </li>
              </ul>
            )
          })
        }
      </div>
    )
  }
}

ReactDOM.render(
  <Welcome/>,
  document.getElementById('root')
)
)

11.生命周期

生命周期即是组件从实例化到渲染到最终从页面中销毁,整个过程就说生命周期,在这个生命周期中,我们有许多可以调用的事件,也俗称为钩子函数

生命周期的3个状态:

  • Mounting:将组件插入到DOM中
  • updating:将数据更新到DOM中
  • unmounting:将组件移出DOM中

生命周期中的钩子函数(方法、事件)

  • componentWillMount:组件将要渲染
  • componentDidMount:组件渲染完毕
  • componentWillReceiveProps:组件将要接受props数据,查看接收props的数据
  • shouldComponentUpdate:组件接收到新的state或者props,判断是否更新。返回布尔值
  • componentWillUpdate:组件将要更新
  • componentDidUpdate:组件已经更新
  • componentWillUnmount:组件将要销毁
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
class ComLife extends Component{
  constructor(props){
    super(props);
    this.state = {
      msg:'hello world'
    }
    console.log('constructor构造函数')
  }
  componentWillMount(){
    console.log('componentWillMount组件将要渲染');
  }
  componentDidMount(){
    console.log('componentDidMount组件渲染');
  }
  componentWillReceiveProps(){
    console.log('componentWillReceiveProps组件将要接收新的state和props');
  }
  shouldComponentUpdate(){
    // 如果希望更新,就返回为真,否则为false
    console.log('进行判断是否要更新内容');
    if(this.state.msg =='hello world'){
      return true;
    }else{
      return false;
    }
  }
  componentWillUpdate(){
    console.log('componentWillUpdate组件将要更新');
  }
  componentDidUpdate(){
    console.log('componentDidUpdate组件更新');
  }
  componentWillUnmount(){
    console.log('componentWillUnmount移除')
  }
  changeMsg = ()=>{
    this.setState({
      msg:'hello'
    })
  }
  render(){
    console.log('render渲染函数')
    return(
      <div>
        <h1>{this.state.msg}</h1>
        <button onClick={this.changeMsg}>组件更新</button>
      </div>
    )
  }
}
class ParentCom extends Component{
  constructor(props){
    super(props);
    this.state= {
      isShow:true
    }
  }
  removeCom = ()=>{
    this.setState({
      isShow:false
    })
  }
  render(){
    if(this.state.isShow){
      return (
        <div>
          <button onClick={this.removeCom}>移除</button>
          <ComLife />
        </div>
      )
    }else{
      return <h1>将comlife已移除</h1>
    }
  }
}

ReactDOM.render(
  <ParentCom />,
  document.getElementById('root')
)

12.React插槽

组件中写入内容,这些内容可以被识别和控制。React需要自己开发支持插槽功能。

原理:
组件中写入的HTML,可以传入到props中。
组件中根据HTML内容的不同,插入的位置不同

import React,{Component} from 'react';
import ReactDOM from 'react-dom';

class ChildCom extends Component{
  render(){
    let headerCom,mainCom,footerCom;
    this.props.children.forEach((item,index)=>{
      console.log(item.props);
      if(item.props['data-position'] === 'header'){
        headerCom = item;
      }else if(item.props['data-position'] === 'main'){
        mainCom = item;
      }else{
        footerCom = item;
      }
      
    })
    return(
      <div>
        <div className='header'>{headerCom}</div>
        <div className='main'>{mainCom}</div>
        <div className='footer'>{footerCom}</div>
      </div>
    )
  }
}

class ParentCom extends Component{
  render(){
    console.log(this.props);
    return(
      <div className='App'>
        <h1>组件插槽</h1>
        {this.props.children}
        <ChildCom>
          <h1 data-position="header">这是放置到头部的内容</h1>
          <h1 data-position="main">这是放置到主要的内容</h1>
          <h1 data-position="footer">这是放置到尾部的内容</h1>
        </ChildCom>
      </div>
    )
  }
}

class RootCom extends Component{
  constructor(props){
    super(props);
    this.state = {
      arr:[1,2,3]
    }
  }
  render(){
    return(
      <ParentCom>
        <h2 data-name='a' data-index={this.state.arr[0]}>子组件1</h2>
        <h2 data-name='b' data-index={this.state.arr[1]}>子组件2</h2>
        <h2 data-name='c' data-index={this.state.arr[2]}>子组件3</h2>
    </ParentCom>
    )
  }
}

ReactDOM.render(
  <RootCom />,
  document.getElementById('root')
)

13.React路由

根据不同的路径,显示不同的组件(内容);React使用的库react-router-dom

安装

cnpm install react-router-dom --save

ReactRouter三大组件:

  • Router:所有路由组件的根组件(底层组件),包裹路由规则的最外层容器.
    属性:basename=>设置此路有根路径,router可以在1个组件中写多个
  • Route:路由规则匹配组件,显示当前规则对应的组件
  • Link: 路由跳转的组件
    注意:如果要精确匹配,那么可以在route上设置exact属性。

Router使用案例

import React,{Component} from 'react';
import ReactDOM from 'react-dom';
// hash模式  哈希模式的变更不会触发请求
// import {HashRouter as Router,Link,Route} from 'react-router-dom';
// history模式 哈希模式的变更不会触发请求,需后端匹配使用
import {BrowserRouter as Router,Link,Route} from 'react-router-dom'; 

function Home(){
  return(
    <div>
      <h1>admin首页</h1>
    </div>
  )
}
function Me(){
  return(
    <div>
      <h1>admin个人中心</h1>
    </div>
  )
}
function Product(){
  return(
    <div>
      <h1>admin产品页面</h1>
    </div>
  )
}

class App extends Component{
  render(){
    return(
      <div id='app'>
        <div>所有页面普通内容</div>
        <Router>
          <Route path='/' exact component={()=>(<div>首页</div>)}></Route>
          <Route path='/me' component={()=>(<div>me</div>)}></Route>
          <Route path='/product' component={()=>(<div>product</div>)}></Route>
        </Router>
        <Router basename='/admin'>
          <div className='nav'>
            {/* <Link to='/'>Home</Link>
            <Link to='/product'>Product</Link>
            <Link to='/me'>个人中心</Link> */}
          </div>
          <Route path='/' exact component={Home}></Route>
          <Route path='/product' component={Product}></Route>
          <Route path='/me' exact component={Me}></Route>
        </Router>
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
)

Link组件可以设置to属性来进行页面的跳转,to属性可以直接写路径的字符串,也可以通过1个对象,进行路径的设置,例如

Link的replace属性:点击链接后,将新地址替换成历史访问记录的原地址

import React,{Component} from 'react';
import ReactDOM from 'react-dom';
// hash模式  哈希模式的变更不会触发请求
// import {HashRouter as Router,Link,Route} from 'react-router-dom';
// history模式 哈希模式的变更不会触发请求,需后端匹配使用
import {BrowserRouter as Router,Link,Route} from 'react-router-dom';

function Home(){
  return(
    <div>
      <h1>admin首页</h1>
    </div>
  )
}
function Me(props){
  console.log(props);
  return(
    <div>
      <h1>admin个人中心</h1>
    </div>
  )
}
function Product(){
  return(
    <div>
      <h1>admin产品页面</h1>
    </div>
  )
}

class App extends Component{
  render(){
    let meObj = {
      pathname:'/me', //跳转的路径
      search:"?username=admin", //get请求参数
      hash:"#abc", //设置的HASH值
      state:{ //传入组件的数据
        msg:'hello world'
      }
    }
    return(
      <div id='app'>
        <Router>
          <div className='nav'>
            <Link to='/'>Home</Link>
            <Link to='/product'>Product</Link>
            <Link to={meObj} replace>个人中心</Link>
          </div>
          <Route path='/' exact component={Home}></Route>
          <Route path='/product' component={Product}></Route>
          <Route path='/me' exact component={Me}></Route>
        </Router>
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
)

动态路由实现

import React,{Component} from 'react';
import ReactDOM from 'react-dom';
// hash模式  哈希模式的变更不会触发请求
// import {HashRouter as Router,Link,Route} from 'react-router-dom';
// history模式 哈希模式的变更不会触发请求,需后端匹配使用
import {BrowserRouter as Router,Link,Route} from 'react-router-dom';

function Home(){
  return(
    <div>
      <h1>admin首页</h1>
    </div>
  )
}
function Me(props){
  console.log(props);
  return(
    <div>
      <h1>admin个人中心</h1>
    </div>
  )
}
function Product(){
  return(
    <div>
      <h1>admin产品页面</h1>
    </div>
  )
}
function News(props){
  console.log(props);
  return(
    <div>
      <h1>新闻页,新闻id:{props.match.params.id}</h1>
    </div>
  )
}

class App extends Component{
  render(){
    let meObj = {
      pathname:'/me', //跳转的路径
      search:"?username=admin", //get请求参数
      hash:"#abc", //设置的HASH值
      state:{ //传入组件的数据
        msg:'hello world'
      }
    }
    return(
      <div id='app'>
        <Router>
          <div className='nav'>
            <Link to='/'>Home</Link>
            <Link to='/product'>Product</Link>
            <Link to={meObj} replace>个人中心</Link>
            <Link to="/news/456789">新闻页面</Link>
          </div>
          <Route path='/' exact component={Home}></Route>
          <Route path='/product' component={Product}></Route>
          <Route path='/me' exact component={Me}></Route>
          <Route path='/news/:id' component={News}></Route>
        </Router>
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
)

重定向组件
如果访问某个组件时,如果有重定向组件,那么就会修改页面路径,使得页面内容显示为所定向路径的内容

import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter as Router,Route,Link,Redirect} from 'react-router-dom';
function LoginInfo(props){
  if(props.location.state.loginState === 'success'){
    return <Redirect to='/admin'></Redirect>
  }else{
    return <Redirect to='/login'></Redirect>
  }
}

let FormCom = ()=>{
  let pathObj = {
    pathname:'/logininfo',
    state:{
      loginState:'success'
    }
  }
  return(
    <div>
      <h1>表单验证</h1>
      <Link to={pathObj}>登录验证后页面</Link>
    </div>
  )
}
class App extends Component{
  render(){
    return(
      <div>
        <Router>
          <Route path='/' exact component={()=>(<h1>首页</h1>)}></Route>
          <Route path='/form' component={FormCom}></Route>
          <Route path='/admin' component={()=>(<h1>admin页</h1>)}></Route>
          <Route path='/login' component={()=>(<h1>登录页</h1>)}></Route>
          <Route path='/logininfo' component={LoginInfo}></Route>
        </Router>
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
)

Switch组件
多个相同path,可匹配多次
让switch组件内容的route只匹配1个,只要匹配到了,剩余的路由规则将不再匹配

import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter as Router,Route,Link,Redirect,Switch} from 'react-router-dom';

function LoginInfo(props){
  if(props.location.state.loginState === 'success'){
    return <Redirect to='/admin'></Redirect>
  }else{
    return <Redirect to='/login'></Redirect>
  }
}

let FormCom = ()=>{
  let pathObj = {
    pathname:'/logininfo',
    state:{
      loginState:'success'
    }
  }
  return(
    <div>
      <h1>表单验证</h1>
      <Link to={pathObj}>登录验证后页面</Link>
    </div>
  )
}
class App extends Component{
  render(){
    return(
      <div>
        <Router>
          <Switch>
            <Route path='/' exact component={()=>(<h1>首页</h1>)}></Route>
            <Route path='/form' component={FormCom}></Route>
            <Route path='/admin' component={()=>(<h1>admin页</h1>)}></Route>
            <Route path='/login' component={()=>(<h1>登录页</h1>)}></Route>
            <Route path='/logininfo' component={LoginInfo}></Route>
            <Route path='/abc' component={()=>(<h1>abc1</h1>)}></Route>
            <Route path='/abc' component={()=>(<h1>abc2</h1>)}></Route>
          </Switch>
        </Router>
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
)
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter as Router,Route,Link,Redirect,Switch} from 'react-router-dom';

function LoginInfo(props){
  if(props.location.state.loginState === 'success'){
    return <Redirect to='/admin'></Redirect>
  }else{
    return <Redirect to='/login'></Redirect>
  }
}

let FormCom = ()=>{
  let pathObj = {
    pathname:'/logininfo',
    state:{
      loginState:'success'
    }
  }
  return(
    <div>
      <h1>表单验证</h1>
      <Link to={pathObj}>登录验证后页面</Link>
    </div>
  )
}

class ChildCom extends Component{
  clickEvent = ()=>{
    console.log(this.props);
    // go(1) 前进1  go(-1)后退
    // goBack 返回
    // goForward 前进
    // this.props.history.push("/",{state:'传递的值'})
    // this.props.history.replace("/",{state:'传递的值'});
    this.props.history.go(1);
    // this.props.history.goBack();
  }
  render(){
    return(
      <div>
        <button onClick={this.clickEvent}>跳转到首页</button>
      </div>
    )
  }
}
class App extends Component{
  render(){
    return(
      <div>
        <Router>
          <Switch>
            <Route path='/:id' exact component={(props)=>{console.log(props);return(<h1>首页</h1>)}}></Route>
            <Route path='/form' component={FormCom}></Route>
            <Route path='/admin' component={()=>(<h1>admin页</h1>)}></Route>
            <Route path='/login' component={()=>(<h1>登录页</h1>)}></Route>
            <Route path='/logininfo' component={LoginInfo}></Route>
            <Route path='/abc' component={()=>(<h1>abc1</h1>)}></Route>
            <Route path='/abc' component={()=>(<h1>abc2</h1>)}></Route>
            <Route path='/child' component={ChildCom}></Route>
          </Switch>
        </Router>
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
)

14.Redux

解决React数据管理(状态管理),用于中大型,数据比较庞大,组件之间数据交互的情况下使用。如果你不知道是否需要使用Redux,那么你就不需要用它!

  • 解决组件的数据通信。
  • 解决数据和交互较多的应用。

Redux只是一种状态管理的解决方案!

  • Store: 数据仓库,保存数据的地方。
  • State: state是1个对象,数据仓库里的所有数据都放在1个state里。
  • Action: 1个动作,触发数据改变的方法。
  • Dispatch: 将动作触发成方法。
  • Reduce: 是1个函数,通过获取动作,改变数据,生成1个新的state,从而改变页面。

安装Redux

cnpm install redux --save
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import {createStore} from 'redux';

// 用于通过动作,创建新的state
// reducer有2个作用,1初始化数据,第二个就是通过获取动作,改变数据
const reducer = function(state={num:0},action){
  console.log(action);
  switch (action.type) {
    case "add":
      state.num++;
      break;
    case "decrement":
      state.num--;
      break;
    default:
      break;
  }
  return {...state}  //相当于对象的copy 变成全新的数据,需要对新的状态进行解构 新版本可以直接返回 return state
}

// 创建仓库
const store = createStore(reducer);

// store里面有dispatch subscibe(监听数据变化) getState replaceReducer 

function add(){
  // 通过仓库的方法dispatch进行修改数据
  store.dispatch({
    type:'add',
    content: {
      id: 1,
      msg: 'hello world'
    }
  })
  console.log(store.getState())
}
function decrement(){
  // 通过仓库的方法dispatch进行修改数据
  store.dispatch({
    type:'decrement'
  })
  console.log(store.getState())
}

// 函数式计数器
const Counter = function (props){
  // 获取数据
  console.log(store.getState());
  let state = store.getState();
  return (
    <div>
      <h1>计数数量:{state.num}</h1>
      <button onClick={add}>计数+1</button>
      <button onClick={decrement}>计数-1</button>
    </div>
  )
}

ReactDOM.render(
  <Counter />,
  document.getElementById('root')
)

// 修改视图(监听数据变化,重新渲染内容)
store.subscribe(()=>{
  ReactDOM.render(
    <Counter />,
    document.getElementById('root')
  )
})

15. react-redux

安装

cnpm install react-redux --save
  • Provider组件:自动的将store里的state和组件进行关联。
  • MapStatetoProps:这个函数用于将store的state映射到组件里的props
  • mapdispatchtoProps:将store中的dispatch映射到组件的props里,实现了方法的共享
  • connect方法:将组件和数据(方法)进行连接。
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider,connect } from 'react-redux';

class Counter extends React.Component{
  render(){
    // 计数,通过store的state传给props,直接通过props就可以将state的数据获取
    const value = this.props.value;
    // 将修改数据的事件或者方法传入到props
    const onAddClick = this.props.onAddClick;
    // 等同于vuex的mapMutation mapState
    return(
      <div>
        <h1>计数的数量:{value}</h1>
        <button onClick={onAddClick}>数字+1</button>
      </div>
    )
  }
}

const addAction = {
  type:'add'
}

function reducer(state={num:0},action){
  switch(action.type){
    case "add":
      state.num++;
      break;
    default:
      break;
  }
  return {...state};
}

const store = createStore(reducer);

// 将state映射到props函数
function mapStateToProps(state){
  return {
    value:state.num
  }
}

// 将修改state数据的方法,映射到props,默认会传入store里的dispatch方法
function mapDispatchToProps(dispatch){
  return {
    onAddClick:()=>{dispatch(addAction)}
  }
}

// 将上面的这2个方法,将数据仓库的state和修改state的方法隐射到组件上,形成新的组件
const App = connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter)

ReactDOM.render(
  <Provider store={store}>
    <App></App>
  </Provider>,
  document.getElementById("root")
)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值