@[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当前,如下的几个生命周期函数都被标记为不平安的,

componentWillMountcomponentWillReceivePropscomponentWillUpdate

当初这几个生命周期函数前都减少了“UNSAFE_”前缀,变成如下模样:

UNSAFE_componentWillMount、UNSAFE_componentWillReceiveProps UNSAFE_componentWillUpdate

因为Fiber重构后,渲染变成了异步的,通过查看新的生命周期图谱,这几个办法都处于原来的render阶段,也就是会呈现反复调用的问题,比如说不合理的应用setState造成反复渲染死循环等。

总结

总的来说,React生命周期的进化都是为Fiber架构服务的,Fiber带了异步渲染的机制,使生命周期变的更加纯正和可控,同时也缩小了咱们书写代码不标准造成的不必要的bug。

感觉文章不错的,给我点个赞哇,关注一下呗! 技术交换可关注公众号【君伟说】,可留言加我好友一起探讨 !