React Class组件详解

5,100 阅读5分钟

创建class组件

class B extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
    <div>hi</div>
    )
  }
}
export default B;

prpos 外部数据

(1)传入props给组件B
class Parent extends React.Component{
  constructor(props){
    super(props)
    this.state = {name:'frank'}
  }
  onClick = ()=>{}
  render(){
    return <B name={this.state.name}
    onClick={this.onClick}>hi</B>
  }
}
super 把接收到的props放到this上,this.props就是外部数据的对象的地址,外部数据被包装为一个对象
{name:'frank',onClick:...,children:'hi'}

(2)初始化 props
class B extends React.Component{
  constructor(props){
    super(props)
  }
  render(){}
}

(3)读取props
class B extends React.Component{
  constructor(props){
    super(props)
  } 
  render(){
    return <div onClick={this.props.onClick}>
      {this.props.name}
      <div>
         {this.props.children}
      </div>
    </div>
  }
}
通过this.props.xxx读取
不能写props,外部数据由它的主人进行更改

(4)props的作用
接受外部数据,只能读不能写,外部数据由父组件传递
接受外部函数,在恰当的时机,调用该函数,该函数一般是父组件的函数

state 和 setState 内部数据

(1)初始化 state
class B extends React.Component{
  constructor(props) {
    super(props);
    this.state = {
      user: {name:'frank', age:18}
    }
  }
render() { /* ... */ }
}

(2)读写state
读用 this.state
this.state.xxx.xxx.zzz
写用this.setState(???,fn)
this.setState(newState,fn)

setState不会立刻改变this.state,会在当前代码运行完之后,再去更新this.state,从而触发UI更新
onClick = ()=>{this.setState((state)=> ({x:state.x + 1}),fn)}   
这种方式的state会立刻执行,fn会在写入时执行

写时会shallow merge
setState会自动将state和旧state进行一级合并

生命周期(Lifecycle)

生命周期类比下面代码

let div = document.createElement('div')
这是div的create/construct过程
div.textContent = 'hi'
这时初始化 state
document.body.appendChidl(div)
这是div的 mount 过程
div.textContent = 'hi2'
这是div的 update过程
div.remove()
这是div的 unmount过程

生命周期函数列表

constructor()                       创建时调用这个函数(在这里初始化state)
static getDerivedStateFromProps()   在调用 render 方法之前调用
shouldComponentUpdate()             组件更新应不应该调用这个函数(return false阻止更新)
render()                            渲染(创建虚拟DOM)
getSnapshotBeforeUpdate()           在最近一次渲染输出(提交到 DOM 节点)之前调用
componentDidMount()                 挂载完就执行函数  (组件已经出现在页面)
componentDidUpdate()                更新就执行函数(组件已经更新)
componentWillUnmount()              将要死亡时执行函数(组件将死)
static getDerivedStateFromError()   此生命周期会在后代组件抛出错误后被调用
componentDidCatch()                 此生命周期在后代组件抛出错误后被调用

constructor

用途
初始化props
初始化state,但此时不能调用setState
可不写constructor,写了必须带super
用来写bind this
  constructor(){
    /*其它代码略*/
    this.onClick = this.onclick.bind(this)
  }
新语法
  onClick = () => {}
  constructor(){/*其它代码略*/}

shouldComponentUpdate()

用途
返回true表示不阻止UI更新
返回false表示阻止UI更新
shouldComponentUpdate() 有什么用
它允许我们手动判断是否要进行组件更新,我们可以根据场景灵活的设置返回值,以不免不必要的更新

示例代码
class App extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      n: 1
      };
    }
    onClick = () => {
      this.setState(state => ({n: state.n + 1}));
      this.setState(state => ({n: state.n + 1}));
  };
    shouldComponentUpdate(newProps, newState){
      if(newState.n === this.state.n){
        return false
      }else{
        return true
      }
  } 
    render(){
      console.log('render了一次')
      return (
        <div>
          {this.state.n}
          <button onClick={this.onClick}>+1-1</button>
        </div>
       );
   }
}
会在render之前,对新旧state进行对比,只进行一层对比(浅对比),如果一样就return false,不更新
将newState和this.state的每个属性都对比一下,如果全都相等,就不更新,如果有一个不等,就更新

React.PureComponent,代替React.Component

render 渲染

用途
展示视图
return (<div>...</div>)
只能有一个根元素
如果有两个根元素,就要用<React.Fragment></React.Fragment>包起来
<React.Fragment></React.Fragment> 缩写 <></>

render里写 if...else
render(){
  let message
  if(this.state.n % 2 === 0){
    message = <div>偶数</div>
  }else{
    message = <span>奇数</span>
  }
  return(
    <>
      {message}
       <button onClick={this.onClick}>+1</button>
    </>
 )
}

render里写?:表达式
render(){
  return(
    <>
       {this.state.n % 2 === 0 ?
          <div>偶数</div> :
          <span>奇数</span>}
          <button onClick={this.onClick}>+1</button>
    </>
  )
}

render里面不能直接写for循环,需要用数组
class App extends React.PureComponent{
  contructor(prpos){
    super(props);
    this.state = {
      n: 1,
      array: [1,2,3] 
      };
    }
  onClick = () =>{
    this.setState(state =>({
      n: state.n +1
    }));
  };
render(){
  let result = []
  for(let i=0;i<this.state.array.length; i++){
    result.push(this.state.array[i])
  }
  return result
  }
}
export dafault App;

render里面写array.map(循环)
class App extends React.PureComponent{
  contructor(prpos){
    super(props);
    this.state = {
      n: 1,
      array: [1,2,3] 
      };
    }
  onClick = () =>{
    this.setState(state =>({
      n: state.n +1
    }));
  };
render(){
  return this.state.array.map(n=><span key={n}>{n}</span>)
  }
}
export dafault App;

componentDidMount()

用途
在元素插入页面后执行代码,这些代码依赖于DOM
首次渲染会执行此钩子
官方推荐,此处可以发起加载数据的AJAX请求

代码示例:获取div的高度
class App extends React.PureComponent{
  contructor(prpos){
    super(props);
    this.state = {
      n: 1,
      width: undefind
      };
    }
  componentDidMount(){
    const div = document.getElementById('xxx')
    const {width} = div.getBoundingClientRect()
    this.setState({width})
  }
render(){
  return (
    <div id='xxx'>Hellow World,{this.state.width}px</div>
    )
  }
}
export dafault App;

使用Ref,不会出现id冲突的情况,先给一个undefined的值在去使用
class App extends React.PureComponent{
  divRef = undefined;
  contructor(prpos){
    super(props);
    this.state = {
      n: 1,
      width: undefind
      };
      this.divRef = React.createRef()                                //创建引用
    }
  componentDidMount(){
    const div = this.divRef.current
    const {width} = div.getBoundingClientRect()
    this.setState({width})
  }
render(){
  return (
    <div ref={this.divRef}>Hellow World,{this.state.width}px</div>   //把引用放在div上
    )
  }
}
export dafault App;

componentDidUpdate()

用途
在视图更新后执行代码
此处也可以发起AJAX请求,用于更新数据
首次渲染不执行此钩子
若shouldComponentUpdate()返回了false,则不会触发此钩子

参数
componentDidUpdate(prevProps, prevState, snapshot) 
                  之前的props 之前的state

componenWillUnmount()

用途
组件将要被移出页面然后被销毁时执行代码
unmount 过的组件不会再次mount

举例
如果你在componentDidMount() 里面监听了windows scroll
那么你就要在componenWillUnmount() 里取消监听
如果你在componentDidMount() 里面创建了Timer
那么你就要在componenWillUnmount() 里取消Timer
如果你在componentDidMount() 里面创建了AJAX请求
那么你就要在componenWillUnmount() 里取消AJAX请求
原理谁污染谁治理

详细资料点击:React 生命周期