13.react生命周期

2020-05-21  本文已影响0人  __疯子__

教程1-14完整项目地址 https://github.com/x1141300029/react-Todos.git

问题:以当前代码,在src/components/TodoList/TodoItem/index.js中的render函数如果添加一行输出的话
1.页面加载的时候回输出两次(没有问题)
2.点击复选框又会输出两次(有问题,应该输出一次,而不是多次)
解释:点击复选框又输出两次,是因为组件进行了重新渲染

参考文档
生命周期图例

1.在src/components/TodoItem/index.js中添加生命周期函数

判断下一次的props和上一次的props是否是一样的,如果一样则不进行更新,shouldComponentUpdate() return false即可

    /**
     * 是否需要更新组件
     * @param nextProps
     * @param nextState
     * @param nextContext
     * @return boolean true更新 false不更新
     */
    shouldComponentUpdate(nextProps, nextState, nextContext) {

        // console.log("-------shouldComponentUpdate-------");
        // console.log(this.props)
        // console.log(nextProps)
        // console.log("-------shouldComponentUpdate-------");


        //如果两个值不相同的情况下才进行页面渲染
        return nextProps.isCompleted!==this.props.isCompleted;
        // return true;
    }

前后值相比较也可以使用框架进行比较 lodashjs
lodash.isEqual使用的是深度比较(递归)比较消耗性能

2.第三种比较方式 src/components/TodoItem/index.js

取消继承`Component`,继承于`PureComponent`
去除生命周期`shouldComponentUpdate`也可以进行比较
这种继承方式属于浅比较
  1. React组件生命周期分为三个部分(挂载、更新、卸载)
    3.1. 挂载卸载过程
    3.1.1. constructor()
1.`constructor()`中完成React数据的初始化
2.`constructor(props,context)`接收两个参数:`props`和`context`
3.如果在函数内部使用这两个参数时,需要使用`super()`传入这两个参数
注意:只要使用了constructor()就必须写super()否则会导致this指向错误

3.1.2. componentWillMount()

`componentWillMount()`一般使用的比较少,它更多是在服务器端渲染时使用。
它代表的过程是组件经历了`constructor()`初始化数据后,但是还未渲染`DOM`时。

3.1.3. componentDidMount()

组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染

3.2.4. componentWillUnmount()

在此处完成组件的卸载和数据的销毁
1. clear你在组件中所有的setTimeout,setInterval
2. 移出所有组件中的监听removeEventListener
3. 有时候我们会碰到这个

> Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a   no-op. Please 
> check the code for the undefined component.

原因:因为你再组件中的ajax请求返回setState,而你组件销毁的时候,请求还没有完成,所以会报warning
解决办法:         ​ 

componentDidMount(){
  this.isMount=true;
    axios.post().then(res)=>{
      this.isMount&&this.setState({//增加条件ismount为true事才进行 setState
      aaa:res
    })
  }
}
componentWillUnmount(){
  this.isMount===false
}
  1. 更新过程
    4.1. componentWillReceiveProps(nextProps)
    4.1.1. 在接收父组件改变后的props需要重新渲染组件的时候用的比较多
    4.1.2. 接收一个参数nextProps
    4.1.3. 通过对比nextPropsthis.props,将nextPropsstate为当前组件的v,从而重新渲染组件
componentWillReceiveProps(nextProps){
  nextProps.openNotice!==this.props.openNotice&&this.setState({
    openNotice:nextProps.openNotice
  },()=>{
    console.log(this.state.openNotice:nextProps);
    //将state更新为nextProps
  })
}

4.2. shouldComponentUpdate(nextProps,nextState)
4.2.1. 主要用于性能优化(部分更新)
4.2.2. 唯一用于控制组件重新渲染的生命周期,由于在react中,setState以后,state发生变化,组件会进入重新渲染的流程,在这里return false可以组织组件的更新
4.2.3. 因为react父组件的重新渲染会导致其子组件的重新渲染,这个时候其实我们是不需要所有子组件都跟着渲染的,因此需要在子组件的该声明周期中做出判断
4.3. componentWillUpdate(nextProps,nextState)
showldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate这样同样可以拿到nextPropsnextState
4.4. componentDidUpdate(prevProps,prevState)
组件更新完毕后,react置灰在第一次初始化成功后进入componentDidmount,之后每次重新渲染都会进入这个生命周期,这里可以拿到prevPropsprevState即更新前的propsstate
4.5. render()
render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染
5.React新增的生命周期
5.1. getDerivedStateFromProps(nextProps,prevState)

代理componentWillReceiveProps()
老版本中componentWillReceiveProps()方法判断前后两个props是否相同,如果不同再进行新的props更新到响应的state上去。这样做以来回破坏state数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重新绘制次数

例如:

//before
componentWillReceiveProps(nextProps){
  if(nextProps.isLogin!==this.props.isLogin){
    this.setState({
      isLogin:nextProps.isLogin
    })
  }
  if(nextProps.isLogin){
    this.handleClose();  
  }
}
//after
static getDerivedStateFromProps(nextProps,prevState){
  if(nextProps.isLogin!==prevState.isLogin){
    return {
      isLogin:nextProps.isLogin
    }
  }
  return null;
}
componentDidUpdate(prevProps,prevState){
  if(!prevState.isLogin&&this.props.isLogin){
    this.handleClose();
  }
}

两者最大的不同就是:

componentWillReceiveProps中,我们一般会做以下两件事,一是根据props来更新state,二是触发一些回调,例如:动画或页面跳转等。

1.在老版的`react`中,这两件事我们都需要在`componentWillReceiveProps`中去做
2.而在新版中,官方将更新`state`与触发回调更新分配到了`getDerivedStateFromProps`与`componentDidUpdate`中,是的组件整体的更新逻辑更为清晰,而且在`getDerivedStateFromProps`中还禁止了组件去访问`this.props`强制让开发者去比较nextProps与prevState中的值,以确保当开发者用到`getDerivedStateFromProps`这个生命周期函数时,就是在根据当前的`props`来更新组件的`state`,而不是去做其他一些让组件自身状态变得更加不可以预测的事情

5.2.getSnapshotBeforUpdate(prevProps,prevState)

代替componentWillUpdate
常见的componentWillUpdate的用例是在组件更新前,读取当前某个DOM元素的状态,并在componentDidUpdate中进行相应处理

区别:
5.2.1. 在React开启一步渲染模式后,在render阶段读取到的DOM元素状态并不总是和commit阶段相同,这就导致在componentDidUpdate中使用componentWillUpdate中读取到的DOM元素状态是不安全的,因为这时的值很可能已经失效了
5.2.2.getSnapshoBeforUpdate会在最终的render之前被调用,也就是说在getSnapshotBeforeUpdate中读取到的DOM元素状态是可以保证与componentDidUpdate中一致的
此生命周期返回的任何职都将作为参数传递给componentDidUpdate()

上一篇 下一篇

猜你喜欢

热点阅读