前言
React16的生命周期相较于React 15有了改进,通过学习React 15和React 16的生命周期,来理解改进的意义。
React15 的生命周期
React的生命周期主要分为三个解读:挂载、更新和卸载。
挂载
当页面进行挂载时主要经历了:constructor -> componentWillMount -> render -> componentMount
这个生命周期。
挂载过程在组件的一生中仅会发生一次,即该过程在生命周期中只会执行一次。这里涉及到钩子主要有:
constructor
:可以对this.state
进行初始化;componentWillMount
:在这一阶段由于JSX被处理为虚拟DOM
,所以此时获取不到DOM
节点,有些人喜欢在这里进行一些初始化的操作,然而会伴随危险;componentDidMount
:此时DOM
已经被挂载在页面中,所以可以操作DOM
,类似于异步请求、初始化操作也可以放在这里。
更新
React
中的更新有两种,一种是由父组件更新触发的更新,一种是组件自身调用自己的setState
触发的更新。
父组件更新触发的更新的生命周期为:componentWillRecevieProps -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
。
组件组我更新时的生命周期为:shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
。
两者的区别在于由于没有触发componentWillRecevieProps
。
这里主要涉及到的钩子有:
componentWillReceviceProps
:当父组件进行更新时,就会触发该声明周期。如果父组件导致组件重新渲染,即使props
没有更改,也会调用此方法,如果只想处理更改,请确保进行当前值与变更值的比较;shouldComponentUpdate
:在更新之前,可以在这个函数内部返回ture||false
来决定组件是否重新渲染子组件(类似pureComponent
);componentWillUpdate
:在render
之前被触发,此时你不可以在这里涉及一些真实的DOM
操作,毕竟此时真实的DOM
还没有在挂载;componentDidUpdate
:在render
之后被触发,意味着更新完成,这时候你可以处理DOM
了。
卸载
组件销毁的时候会触发该方法,而组件销毁有两种原因:一种是组件在父组件中被移除了;一种是组件设置了key
,父组件在render
的过程中,发现key
的值和上一次不一致,那么这个组件就会被销毁。
这里涉及到的钩子是:
componentWillUnmount
。
React16 的生命周期
挂载
当页面进行挂载时主要经历了:constructor -> getDerivedStateFromProps -> render -> componentMount
这个生命周期。
React16中废弃了componentWillMount
,使用了getDerivedStateFromProps
,它不是前者的替代品,毕竟作用不一样。getDerivedStateProps
仅用来使用props
来派生/更新state
。
static getDeriviedStateFromProps(props, state)
- 由于这是一个静态方法,所以获取不到
this
; - 该方法接受父组件传递进来的
props
和当前组件自身的state
; - 需要以对象格式的返回值
更新
父组件更新触发的更新的生命周期为:getDerivedStateFromProps -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate
。
组件组我更新时的生命周期为:shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate
。
由此可见,React 16中更新了两点:
- 移除了
componentWillReviceProps
,使用了getDrivedStateFromProps
。由上面可知getDerivedStateFromProps
不能操作this
,只完成props
派生/更新state
,比起componentWillRevice
能做的事情少了很多,即使用了减法
,减少了副作用(如修改state
、使用fecth
获取数据等操作)。 - 移除了
componentWillUpdate
,使用了getSnapshotBeforeUpdate
。getSnapshotBeforeUpdate
的返回值会作为第三个参数传递给componentDidUpdate
,它的执行机制是在render
之后,真实DOM更新前,在这里可以获取到更新前的真实DOM,和更新前后的state/props
。
卸载
React 16的卸载过程与React 15一致。
Fiber
Fiber是React 16对React核心算法的一次重写,它会使原本同步的渲染过程变成异步的。
在React 16之前,React的渲染模式是同步的,每次更新的时候,对比两个虚拟DOM,然后进行更新,这个更新过程是递归的过程。同步渲染的递归栈是特别深的,只有最底层的渲染返回了,才会逐层返回,由于主线程被占有用,无法做其他事情,这个漫长且不可打断的过程会导致页面白屏、卡顿等严重问题,
React 16之后,将渲染模式调整为异步模式,将渲染任务拆分为多个小任务,当一个小任务完成之后,交会主线程,可以指定下一个优先级较高的任务进行渲染,渲染过程中可以被打断。
为什么要改进生命周期
Fiber的主要特征就是可以异步渲染,实现这一目标却决与渲染过程中是否能被打断。
React 16的声明周期被划分为render
和commit
(含pre-commit
)两个阶段:
render
阶段:是纯净的且没有副作用,可以被React暂停、终止或者重启;pre-commit
:可以读取真实的DOM
;commit
:可以使用DOM
,运行副作用,安排更新。
render
阶段在执行过程中运行被打断,而commit
阶段总是同步执行的。(render
用户不可见,所以可以被打断,但是commit
是可以操作DOM
,是可见的,所以是同步的)。
React 16废弃了的componentWillMount、componentWillUpdate、componentWillReviceProps
都处于render
阶段,都可能被重复执行,而且这些API常年被滥用,会产生一系列的副作用:
- 习惯在
componentWillxxxx
下的Fetch
数据,这些完全可以转移到componentDidXXX
中去做,异步请求再快也快不过同步的生命周期,首次渲染依然会在数据返回之前执行; - 在
render
阶段里的生命周期可以被重复执行,在componentWillXXX
被打断+重启多次后可能会发起多个付款请求。
React 16改造生命周期的主要动机就是为了配合Fiber架构带来的异步渲染机制。
总结
- React 16废弃了
componentWillMount、componentWillReviceProps、componentWillUpdate
,引入了getDerivedStateFromState
和getSnapshotBeforeUpdate
; - React 16中,挂载的生命周期为:
constructor -> getDerivedStateFromProp -> render -> componentDidMount
; - React 更新的生命周期触发条件由两种,一种是父组件更新,一种是子组件自身调用
setState
进行更新,前者的生命周期为:getDerviedStateFromState -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate
,后者的生命周期为:shoundComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate
; - React的卸载阶段会执行
componentWillUnmount
。 getDerviedStateFromProps
和getSnapshotBeforeUpdate
都是静态方法,所以不能使用this
,可以避免骚操作,前者在render
之前执行,后者在redner
之后执行,可以操作更新前真实的DOM和更新前后的state/prop
;- Fiber是React 对Reacte核心算法的重新,主要将同步渲染改为异步渲染,提高渲染效率;
- 渲染阶段分为
render
阶段、commit
阶段,render
对用户不可见,所以是异步的,commint
可以获取真实的DOM
,对用户可见,是同步的; constructor、getDerivedStateFromProps、render、shouldCompoent
属于render
阶段,可以被暂停、终止和重启,getSnapshotBeforeUpdate
属于pre-commit
,这里可以获得DOM,componentDidMount、componentDidUpdate和componentWillUnmount
属于commit
阶段;componentWillMount、componentWillReviceProps和componentDidUpdate
由于长期被滥用,可能会创建一些副作用,且位于render
阶段,无法避免若重复执行带来的危害性,为了配合Fiber架构,所以React 16对这三个钩子进行了移除。
参考
如有错误,欢迎指出,感谢~