React -- 类式组件的生命周期

164 阅读5分钟

一. 老生命周期

<1> 初始化阶段

(1) componentWillMount()

这个生命周期已经不推荐使用了,因为在 react 近期的版本中,为了优化 DOM diff 渲染算法 ,采用了 fiber 技术,该技术核心思想是把DOM diff 渲染算法划分成一个一个小任务,并且每个任务都有优先级高低,比如,马上要render()展示的组件的优先级就高,所以就会先执行该部分代码,由于 componentWillMount 是马上要挂载,但还没挂载,所以优先级就低,所以就会被优先级高的任务抢断,就可能会导致 componentWillMount() 被执行多次,从而有忧患!!!

  • 如果硬要使用的话,前面加上 "UNSAFE_" ,即 UNSAFE_componentWillUpdate() 就不会出现 warning!!!
(2) render()

每次状态更新都会被调用执行!!!

so注意:

  • 不要在 render() 中执行,setState() ,会造成死循环,因为状态更新,就会再次调用 render() ,同时就会再次执行setState()....

  • 一般只做组件展示,只访问 state 和 props

(3) componentDidMount()
  • 成功 render() 并渲染完成真实 DOM 之后触发
  • 数据请求 ajax 、axios
  • 订阅函数的调用
  • setInterval()
  • 可以在里面进行 DOM 节点的修改 ,BetterScroll(一个库,可以使 DOM 节点中的内容,更平缓的滚动!!)

<2> 运行中

(1) componentWillUpdate()

componentWillMount() 一样已经不推荐使用了!!

(2) render()

不要在里面更新状态 setState()

(3) componentDidUpdate()

更新后执行,可以在里面获取 DOM 节点,并进行更新!!!

componentDidUpdate(preProps , preState)

  • 该函数会收到两个参数,即更新前的属性和状态!!!

注意:

  • 该生命周期函数跟 render() 一样会执行很多次,所以里面的操作也会执行很多次,考虑到性能问题,可以给部分操作加上判断条件,实现只在首次渲染执行一次的操作!!!

1860.png

(4) shouldComponentUpdate() 性能优化函数

shouldComponentUpdate(nextProps , nextState)该函数接收两个参数,想要更新的属性和状态!!

1861.png

注意:

  • 如果有多个状态,一个一个比太麻烦了,所以可以将整个状态对象转化为字符串进行对比。JSON.stringify()

1863.png

在子组件中用的多!!!

例如,我们要在父组件中遍历生成若干个我们自己写的 child 组件 ,如果我们不在子组件中做性能优化的话,那么每次父组件状态改变,导致子组件的重新 update 的话,有多少个子组件,就会 render() 多少次!!!!所以我们可以在子组件中使用 shouldComponentUpdate() 做性能优化,只有状态因为父组件的改变而跟着改变的子组件才用 render() !!!

1864.png

1865.png

注意:

前面提到的,不要直接 this.state.cnt = 1修改状态的原因是,如果要用 shouldComponentUpdate(nextProps , nextState) 这个函数,那就要进行老状态与想要更新的状态的对比,如果直接修改的话,那么老状态就会被改变了,那么该函数就会变的毫无意义!!!

(5) componentWillReceiveProps(nextProps)

在子组件中使用!!!!

最先获得父组件传来的属性(nextProps),可以在该函数中对该传来的属性进行处理!!!AJAX or 逻辑处理(把属性转换为自己的状态...)!!!

<3> 销毁

(1) componentWillUnmount()

在组件被卸载之前进行一些清理操作,如清除计时器、关闭事件监听器!!!

1866.png

二. 新生命周期

<1> getDerivedStateFromProps()

getDerivedStateFromProps(nextProps , nextState)

第一次的初始化组件 && 后续的更新过程中(包括自身状态更新以及父传子属性更新)都会执行该函数!!

返回一个 对象,作为新的 state ,会跟之前的 state 对象进行合并 ,即没有的添加,同名的进行更新!!

注意:

  • 该函数为类上的静态方法,即使用要在前面加上static

  • 因为是类本身上的方法,所以无法在其内部使用this

  • 因为该函数返回新的 state 对象,所以在里面发起请求,ajax、axios是没有用的,因为该函数会直接执行返回的代码,即请求接收到的数据,是无法被即使作为新状态对象返回出去的!!!

    • 所以该函数可以配合 componentDidUpdate() 使用,即在该函数中把接收到的属性转化为自身的对象,然后在 componentDidUpdate() 进行使用!!

all in all:

  • 该新的生命周期可以在初始化时代替 componentWillMount()
  • 在父传子中可以代替 componentWillReceiveProps()

<2> getSnapshotBeforeUpdate()

触发时间为 update 发生的时候,执行时间为render()之后,DOM 发生更新之前 ,所以常常用来记录 DOM 更新之前的一些数据!!供更新后使用!!!

  • 例如,用户在浏览邮箱页面,突然来了很多封新邮件,那么就需要对它们进行展示,而且是要展示在头部,所以如果不加处理用户正在看的地方就会被推到下面,为了更好的用户体验,我们希望,此时还保留在用户之前停留的页面!!!

       - 就需要记录下之前的容器高度,然后在新的邮件进行展示后,将页面滚动到 `scrollTop = 此时容器高度 - 之前容器高度` !!
    

它可以很好地替代 componentWillUpdate()componentWillUpdate() 执行时间为 render() 之前,所以从记录之后到开始更新 DOM 之间间隔时间还挺长的,所以会导致记录的数据不准确!!!

1867.png

  • 该函数返回记录的数据,并且该返回的值会作为参数传入 componentDidUpdate() ,作为它的第三个参数,即 componentDidUpdate(preProps , preState , value) ,方便在内部进行一些操作!!!