@[toc]
前言
家喻户晓每个利用的开发框架都有其对应的生命周期函数,ReactNative 是基于 React 开发的,所以其生命周期先关函数也和 React 一样密不可分,为什么文章题目叫“生命周期的进化”呢?这是有起因的,因为 React 在 React 15 和 React 16 两个版本对生命周期函数做了优化调整,到底进行了那些调整和改良呢?让咱们随着本文一探到底。
React 15 生命周期函数
上面这张图是一个典型的 React 15 的生命周期函数流程图,也是咱们大多数开发者所理解到的。
React 15 相干的生命周期函数如下:
constructor()
componentWillReceiveProps()
shouldComponentUpdate()
componentWillMount()
componentWillUpdate()
componentDidUpdate()
componentDidMount()
render()
componentWillUnmount()
Mounting 阶段:组件初始化渲染
初始化渲染阶段次要波及如下几个生命周期函数:
constructor()
componentWillMount()
render()
componentDidMount()
constructor()这个函数只在组件初始化的调用一次,通常开发中次要用于对 state 的数据初始化。
componentWillMount(),componentDidMount()函数在组件初始化阶段也只调用一次,componentWillMount()在 render()函数执行之前被调用,有些同学开发中会在此函数中做网络申请, 想想会有哪些危险呀?
之后触发 render()办法进行渲染页面,但此时不会去操作实在 DOM, 只是把要渲染的页面返回解决,真正解决是通过 ReactDOM.render 办法在页面挂在阶段实现的。
componentDidMount()函数会在实在 DOM 挂载实现时候调用,通常开发中咱们在此函数进行网络申请,音讯监听等来操作实在的 DOM。
Updating 阶段:组件更新
组件的更新分为两种:一种是父组件的更新触发的更新,另一种是组件本身调用 this.setState()触发的更新。
组件更新过程中波及的如下生命周期函数:
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()
首先看一下 componentWillReceiveProps(nextProps), 这个函数参数中 nextProps 示意承受到的新 props,能够用来和 this.props 进行比照,看是否扭转。
请留神,如果父组件导致组件从新渲染,即便 props 没有更改,也会调用此办法(componentWillReceiveProps)。如果只想解决更改,请确保进行以后值与变更值的比拟。
—— React 官网文档
关键点:也就是 componentWillReceiveProps()函数不是 props 扭转触发的,而是因为父组件更新触发的。
shouldComponentUpdate(nextProps, nextState)函数在组件本身的 state 产生扭转时触发,该函数的返回值决定了组件是否从新 render, 默认返回“true”,示意只有是 state 产生更新,就会从新 render;理论开发工作中,咱们个别会比照函数中的参数来进行业务逻辑判断是否须要从新 render。这也是一个 React 提供给咱们的一个性能优化的方向之一。
componentWillUpdate()与 componentDidUpdate()是在 render 前后进行触发的,对应于 componentWillMount()和 componentDidMount()。componentDidUpdate 在组件更新实现之后触发,能够操作实在 DOM。
Unmounting 阶段:组件卸载
这个阶段就比较简单了,只有一个生命周期函数:
componentWillUnmount()
在组件卸载和销毁之前会触发 componentWillUnmount()函数,理论开发中咱们通常进行如下操作,比方革除定时器 timer, 勾销网络申请或者革除在 componentDidMount() 中创立的订阅等。
进化:React 16 生命周期函数
下面节选咱们回顾了 React 15 的生命周期函数,那么 React 16 有那些更新和改良呢?其中 16.3 版本和 16.4 版本的生命周期稍有不同,首先咱们一起来 16.3 版本的流程图 React 16.3 Lifecycle
设计到的生命周期函数如下:
constructor()
getDerivedStateFromProps()
getSnapshotBeforeUpdate()
shouldComponentUpdate()
componentDidUpdate()
componentDidMount()
render()
componentWillUnmount()
Mounting 阶段:组件初始化阶段(挂载)
在 React 16 的 mounting 阶段波及到的生命周期函数如下:
constructor()
getDerivedStateFromProps()
componentDidMount()
render()
React 16 和 React 15 相比在初始化阶段,多了一个 getDerivedStateFromProps()函数,少了一个 componentWillMount()函数。
那 getDerivedStateFromProps()是用来替换 componentWillMount()函数的吗?
首先咱们看一下这个函数
static getDerivedStateFromProps(props, state)
这是一个动态的函数,并且须要返回一个对象用来更新 state,如果返回 null,则不会更新 state。
对于此函数须要理解三个要害重要的点。
第一个这是一个动态函数,所以在这个函数中不能拜访 class 的实例,也就是说不能在函数中应用 this 通过 this.props 的获取数据。
第二个此函数承受两个参数 props 和 state,props 是指父组件传递的 props,state 指的是本身的 state。
第三个此函数须要一个对象格局的返回值,因为须要依据这个返回的数据来更新 state, 如果不须要更新 state,就返回一个 null, 如果什么都不返回,就会收到正告,或者罗唆不从新这个函数。
Updating 阶段:组件更新阶段
在更新阶段波及到的函数有一下几个:
getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
在更新阶段,16.3 和 16.4 略微有些不同,来看一下流程图
比照 16.3 和 16.4 的流程图咱们发现,变动的局部是 getDerivedStateFromProps()的触发机会,次要的变动体现在
如下两个方面:
1.React 16.4 版本中 getDerivedStateFromProps()在父组件更新承受 props, 组件本身调用 setState()函数以及 forceUpdate()函数执行时都会被触发
2.React 16.3 在更新阶段只有父组件更新才会触发。
比照 React 15, 咱们发现 React 16 版本少了 componentWillReceiveProps()以及 componentWillUpdate(),减少了 getDerivedStateFromProps()和 getSnapshotBeforeUpdate()。
咱们晓得 React 15 中父组件产生更新后会触发 componentWillReceiveProps()函数,而本身 setState 的时候不会触发,而在 React 16 中组件任何更新都会触发 getDerivedStateFromProps()函数,这种改良是为什么呢?
对于 getDerivedStateFromProps,React 给出的解释是:
与 componentDidUpdate 一起,这个新的生命周期涵盖过期 componentWillReceiveProps 的所有用例。
能够看出这个新函数不仅仅是 componentWillReceiveProps 的简略代替,其办法被定义成了 static,即在办法外部能不能拜访 this, 那么就可能防止谬误的操作,比方应用 this.fetch 进行网络申请,应用 this.setSate 进行 render 造成死循环。
因而 getDerivedStateFromProps 的存在只有一个目标:让组件在 props 变动时更新 state。
对于此函数的应用,官网也给出了倡议:
留神:旧的 componentWillReceiveProps 和新的 getDerivedStateFromProps
办法都会给组件减少显著的复杂性。这通常会导致 bug。思考 派生 state 的简略代替办法 使组件可预测且可保护。
接下来看 getSnapshotBeforeUpdate,React 官网的解释:
与 componentDidUpdate 一起,这个新的生命周期涵盖过期的 componentWillUpdate 的所有用例。
getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate() 在最近一次渲染输入(提交到 DOM 节点)之前调用。它使得组件能在产生更改之前从 DOM 中捕捉一些信息(例如,滚动地位)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。
在这个函数外面能够拿到更新前的实在 DOM 和更新后的最新 props 和 state.
最初看一下 componentDidUpdate 函数
componentDidUpdate(prevProps, prevState, snapshot)
如果组件实现了 getSnapshotBeforeUpdate() 生命周期(不罕用),则它的返回值将作为 componentDidUpdate() 的第三个参数“snapshot”参数传递。否则此参数将为 undefined。
Unmounting 阶段:组件卸载
在卸载阶段 React 16 和 React 15 一样,没有发生变化,都只波及一个生命周期函数:
componentWillUnmount()
componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会从新渲染。组件实例卸载后,将永远不会再挂载它。
生命周期进化的起因
React 的生命周期发生变化和改良的起因都是因为 React 我的项目应用成为“Fiber”的外围架构重写了 React。
Fiber 使原来 React 15 的同步渲染变成了异步渲染,防止阻塞 React 主线程。
在 React 16 之前,咱们应用 setState 更新组件,React 都会生成一个新的虚构 DOM, 通过与上一次的 DOM 进行 diff 比照后,再定向更新实在的 DOM。这是一个同步渲染的递归过程,就如同走楼梯一样。
如果页面的布局简单嵌套很深,那么递归调用的工夫就会很长,那么的主线程就会被 js 始终占用着,任何交互,布局,渲染都会进行,那给用户出现的画面就是很卡顿。
而应用 Fiber 重构之后就解决了这个问题,Fiber 将漫长的更新工作进行切片成小工作。执行完一个小工作,就将主线程替换回去,看看是否有优先级更高的工作须要解决,这样就防止了同步更新造成 UI 阻塞的问题。
应用 Fiber 进行切片后,异步的渲染工作就变成了可打断的,执行过程就变成了如下的模式:
应用 Fiber 背地的故事
在 React 16 当前,如下的几个生命周期函数都被标记为不平安的,
componentWillMount
componentWillReceiveProps
componentWillUpdate
当初这几个生命周期函数前都减少了“UNSAFE_”前缀,变成如下模样:
UNSAFE_componentWillMount、UNSAFE_componentWillReceiveProps
UNSAFE_componentWillUpdate
因为 Fiber 重构后,渲染变成了异步的,通过查看新的生命周期图谱,这几个办法都处于原来的 render 阶段,也就是会呈现反复调用的问题,比如说不合理的应用 setState 造成反复渲染死循环等。
总结
总的来说,React 生命周期的进化都是为 Fiber 架构服务的,Fiber 带了异步渲染的机制,使生命周期变的更加纯正和可控,同时也缩小了咱们书写代码不标准造成的不必要的 bug。
感觉文章不错的,给我点个赞哇,关注一下呗!技术交换可关注公众号【君伟说】,可留言加我好友一起探讨!