React 15 组件的生命周期
挂载阶段:
constructor componentWillMount render componentDidMount
更新阶段:
- 由父组件触发:componentWillReceiveProps shouldComponentUpdate componentWillUpdate render componentDidUpdate
- 组件本身调用 setState 触发 shouldComponentUpdate componentWillUpdate render componentDidUpdate
卸载阶段:
comonentWillUnmount
另外:
- render 不会操作真实 DOM,只会把要渲染的内容返回出来,真实的 DOM 渲染工作在挂载阶段是由 reactDOM.render 来承接的。
- 子组件的 componentWillReceiveProps方法是由父组件的更新来触发的,而不是因为props 的变化。
- shouldComponentUpdate(nextProps , nextState) 根据返回值确定之后的生命周期。
React 16 生命周期的变化
React 16.3
React 16.4+
变化之一:getDerivedStateFromProps(props,state)
相对于React15来说,在挂载阶段,去掉了 componentWillMount 这个没什么用的方法,在由父组件引起的更新阶段,替换掉了 componentWillReceivePorps ; 同时引入了getDerivedStateFromProps,用props来派生state ,组件挂载和更新阶段此方法均会被调用,因为在组件挂载时,也是有用props派生state的需求的。
此方法为静态方法,和具体的组件实例无关,所以在它内部无法使用this。它可以返回一个对象,这个返回的对象会被合并到当前组件的state对象里,这大概就是派生state的意思。
变化之二:getSnapshotBeforeUpdate(prevProps,prevState)
此方法在组件更新阶段,运行于render方法之后,一般和componenDidUpdate方法成对使用.
getSnapshotBeforeUpdate的返回值会被传入 componentDidUpdate,因为它的执行时机是 render 方法之后 ,真实 DOM 更新之前,所以可以获取到更新前后的state&props信息
componentDidUpdate(prevProps,prevState,valueFromSnapshot)
更深层的原因
因为React 16 引入的Fiber机制,把同步的渲染流程进化为了异步的渲染流程,这么做的原因是同步渲染流程有个弊端:一旦开始就不能停下,大工作量的渲染任务执行时,主线程会被长时间的占用,浏览器无法响应与用户的交互。
Fiber 机制会把渲染任务拆解为多个小任务,并且每执行完一个小任务,就把主线程的执行权交出去,也就解决了上面的弊端。
然而,采用Firber 机制进行渲染时,render 阶段没有副作用,可以被暂停,终止或重新启动。就是这个重新启动,会导致工作在 render阶段的 componentWillMount componentWillReceiveProps componentWillUpdate 存在重复执行的可能,所以它们几个必须被 “优化掉”
总结
React 16 基于两个原因做出了生命周期的调整,
-
其一:为同步渲染改异步渲染的 Fiber 铺路,把有可能多次执行的 render 阶段中 componentWillMount/componentWillUpdate/componentWillRecevieProps 三个方法弃用;
-
其二:为在一定程度上防止用户对生命周期的错用和滥用,把新增的 getDerivedStateFromProps 用 static 修饰,阻止用户在其内部使用 this 。