# 简介

# 组件声明方式

# 函数组件

函数组件没有自己状态和生命周期,但基于函数的概念可以延展出很多React的高级玩法,HOC、纯展示组件、或者16.8版本后HOOK增强后对函数组件新增的多个API几乎大部分类组件的功能都能通过HOOK来很好的解决。

  function App(){
  return(
    <div>123123</div>
  )
}

# 类组件

# Component

使用该方式继承的组件有React的生命周期函数和状态等特性 例子:

class ReactComponent extends React.component{
  constructor(props){//ES6类构造函数 用于接收传递的参数,不接受React默认接收并传递给props对象
    super(props)//调用父类的构造方法
    //执行react类组件初始化代码,如接收props并赋值到状态中
    this.state={
      name:"CJ"
    }
  }
  render(){//渲染的JSX语法结果
    return(
      <div> this is a react component{this.state.name}</div>
    )
  }
}

# PureComponent

PureComponent是对Component的性能优化,只做接收props并展示的功能,但是比函数组件多了状态和生命周期,就像是使用了shouldComponentUpdate()函数对props类型为对象时不渲染改变的结果,所以使用PureComponent的组件接收的props父组件中改动了自身也不会有任何变动。 具体使用方法和原Component一样。

# 生命周期

借由官网生命周期图标 先来看看再React类组件中的各种钩子函数:

  • constructor: 类构造器函数,最先执行,组件初始化等,用来接受props和其他值(已默认接收)
  • componentWillMount:组件挂载前执行
  • render: 执行渲染函数,返回JSX功能(Babel编译成createElement形式)
  • componentDidMount:组件挂载完毕的函数。
  • componentWillReceiveProps:即将废弃:组件所接受的props发生改变时执行的函数,只要父组件render被调用,该函数就会被触发 组件更新时依次执行的函数
  • shouldComponentUpdate:性能优化函数,主要用来控制该组件是否重新渲染。
  • componentWillUpdate:传递状态改变前的值
  • render:重新调用渲染函数渲染。
  • componentDidUpdate:
  • componentWillUnmount:卸载组件

# Context

contextAPI为16.3后新增,在组件化开发中,如何跨组件优雅的共享状态一直是很棘手的问题,常见的作法也有很多,使用状态管理(引入第三方react-redux,mobx等),嵌套多层的props,使用contextAPI等,用来处理平行组件或跨多层组件之间的通信问题,例如:全局的主题动态配置、处理全局状态(用户登录状态)、数据持久化(存储)等等。Context API用于多组件跨级传值,使用React.createContext()创建对象,该对象下有Provider和Consumer两个对象(生产者和消费者),生产者用于包装需要分享状态的组件,消费者用来接收参数。

import React from 'react';
const {Provider,Consumer} = React.createContext();//创建生产者和消费者
export {Provider,Consumer}//导出

父组件从文件导入生产者

import {Provider} from './xxx.js';
import React from 'react';
class App extends React.Component{
  constructor(props) {
    super(props);
    this.state = {value:'this is Context info'}
}
  render(){
    return(
      <div>
      <Provider value={this.state.value}>
        <Child></Child>
      </Provider>
      </div>
    )
  }
}
export default App;

组件内的所有子组件可接收并共享该数据状态,Consumer组件内函数传递的参数即为context共享的对象,即调用setState参数修改该参数时,视图层也会做出响应。

import React, {Component } from 'react'
import {Consumer} from './xxx.js' //导入消费者
class HashRouter extends Component {
    render() { 
        return (
            <Consumer>
                {state=>(
                    console.log(state) //this is Context info
                )}
            </Consumer>
        );
    }
}
 
export default HashRouter;

# 代码切割

# 高阶组件(HOC)

高阶组件类似与高阶函数,用与对组件添加增强功能,如:操纵原组件props,增强生命周期函数,增加额外的状态,以及类似vue中的mixin组件增强,react中并没有此类API,可通过代码实现mixins功能,更多HOC高阶特性玩法还有很多。。。

# 操纵组件props

import React from 'react';
import ReactDom from 'react-dom';
class App extends React.Component{
  render(){
    return(
      <div>{this.props.name}{this.props.age}</div>
    )
  }
}
function HocPropsFunc(WrapComponent){
  let props={
    name:'CJ',
    age:23
  }
  return <WrapComponent {...props} />;//添加props给原组件使用
}
ReactDOM.render(
  HocPropsFunc(App),
  document.getElementById('root')
);

# 再次返回类组件增强更多功能

class App extends React.Component{
    state={};
    componentDidMount(){
      console.log('didmount')
    }
    render(){
      return(
        <div>{this.props.name}</div>
      )
    }
  }
  function HOCClassFunction(WrapComponent){
    return class extends React.Component{
        componentDidMount(){
            console.log("WrapComponetn init")//此处可在返回的组件中执行更多
            //组件的操作,从而扩展更多功能
        }
        state={
            name:'CJ',
            age:23
        }
      render(){
        return <WrapComponent {...this.state} />
      }
    }
  }
  ReactDOM.render(
  HOCClassFunction(App),
  document.getElementById('root')
);

# 修改组件生命周期函数或修改state状态(mixins)

let ReactMinxins={//自定义mixins对象,可添加React生命周期函数或者一些辅助函数等
    componentDidMount(){
        console.log(" minxins COmponentWillMount");
    }
}
class App extends React.Component{
    state={};//此处必须有一个state对象,否则增强状态时报错找不到对象函数
    componentDidMount(){
      console.log('class didmount')//原生命周期函数
    }
    render(){
      return(//显示增强后的name
        <div>{this.state.name}</div>
      )
    }
  }
  function mixinFunction(WrapComponent){//简易实现基于React的mixins功能
    let prevFn=WrapComponent.prototype.componentDidMount;//暂存componentDidMount函数
    WrapComponent.prototype.componentDidMount=function(){//重写该函数,此处不能使用
    //箭头函数,否则this指向mixinFunction
      prevFn();//执行暂存的原组件的生命周期方法
      this.setState({//像原组件添加状态
        name:"DJ",
        age:23
      })
      ReactMinxins.componentDidMount();//调用执行mixins方法
    };
    return WrapComponent//返回增强后组件
  }
    ReactDOM.render(
    mixinFunction(App),
  document.getElementById('root')

# Hook

React 16.8Hook的出现,官方极力推崇函数式编程,在不使用类的情况下使函数组件也有自己的state,由此新增了多个API,极大增强了函数组件。原有create-react-app 创建的项目只要将react和react-dom升级到16.8以上版本即可使用Hook特性。

# useState

顾名思义,该API是函数组件最常用的,他替代了类组件的this.state,使得函数组件也有自己的状态,调用解构的第二个函数传递新参数时刷新视图。
一个简单的累加计数:

import React ,{useState}from 'react';

function App(){
  const [count,setCount]=useState({num:0,name:'CJ'});
  //解构出第一个参数为对象,第二个修改参数的方法(该方法并不会像是setState那样自动合并对象
  //而是整个替换掉,所以当第一个参数为对象时,最好使用{...count,xxx:'changeObj'}
  return(
    <div>
        {count.num}
        <button  onClick={()=>{
          setCount({...count,num:count.num+1})
        }}>increment</button>
    </div>
  )
}

延迟加载:

  const [count,setCount]=useState(()=>{
    return initPams(5)//调用函数初始化状态
  });
  function initPams(arg){
    return arg+5
  }
  return(
    <div>
        {count}
        <button  onClick={()=>{
          setCount(count+1)
        }}>increment</button>
    </div>
  )

# useEffect

useEffect用来监听一些非DOM渲染数据也需要进行更改时,例如document.title,window.href,或者添加监听事件等,返回事件在组件清除时对监听事件解除绑定。函数内数据每次触发一次渲染修改,会自动执行该函数。

import React ,{useState,useEffect}from 'react';
export default function (){
  const [title,setTitle]=useState('is Title');
  useEffect(()=>{
    document.title=title;
    return()=>{
      document.title='React app'
    }
  });
  return(
    <div>
        {title}
        <button  onClick={()=>{
            setTitle(title+'+')
        }}>AddTitle</button>
   
    </div>
  )
};

# useMemo

useMemo类似Vue中的computed,监听多个函数,在函数变动时触发指定的函数执行。在vue中只要该函数内的data变动后便会立即执行,重新渲染最新的结果,复杂的业务中,并不是所有结果都是由其本身的影响生成,亦可能是其他数据的变动改变导致重新渲染,useMemo与computed最大的差别就是是否自动检测渲染。

import React ,{useState,useMemo}from 'react';
export default function (){
  const [count,setCount]=useState(0);
  useMemo(()=>{
    console.log(count)//此时的取值是更新之前的值
  },[count])//第二个参数决定哪些数据变动触发函数执行
  return(
    <div>
        {count}
        <button  onClick={()=>{
            setCount(count+1)
        }}>Increment</button>
   
    </div>
  )
};

# useCallBack

useCallBack类似于类组件每次setState完后传递的callBakc函数,用来获取最新的值,在类组件中异步改变state中的数据后必须在回调函数中才能获取最新的状态,例:

this.setState({count:0},()=>{
  console.log(this.count)//此时才能获取罪行的状态
})

使用useCallBack:

import React ,{useState,useCallBack} from 'react';
 function App(){
      const [count,setCount]=useState(0);
      let countCb=useCallback(()=>{
      console.log(count)
      },[count])
      countCb();
      return(
          <div>
              {count}
              <button  onClick={()=>{
                  setCount(count+1)
              }}>Increment</button>
        
          </div>
        )
 }

# Router