React生命周期

95 阅读5分钟

react16之前

componentWillMount: 渲染前调用,客户端、服务端均可。

componentDidMount :第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。

componentWillReceiveProps:在组件接收到一个新的prop (更新后)时被调用。这个方法在初始化时的渲染中不会被调用

shouldComponentUpdate:返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate不被调用。可以在确认不需要更新组件时使用。

componentWillUpdate:在组件接收到新的props或者state,但还没有render时被调用。在初始化时不会被调用

componentDidUpdate:在组件完成更新后立即调用。在初始化时不会被调用。

componentWillUnmount:在组件从DOM中移除之前立刻被调用。

初始化:

在类的构造方法( constructor()中,组件类继承了react Component这个基类,也就继承这个react的基类,才能有render(),生命周期等方法可以使用,这也说明为什么函数组件不能使用这些方法。

挂载:

componentWillMount:

在组件挂载到DOM前调用,且只会被调用一次,在这边调用this.setState不会引起组件重新渲染,也可以把写在这边的内容提前到constructor()中,所以项目中很少用。

render:

根据组件的props和state(无两者的重传递和重赋值,不论值是否有变化,都可以引起组件重新render) ,return一个React元素(描述组件,即UI),不负责组件实际渲染工作,之后由React自身根据此元素去渲染出页面DOM。render是纯函数(Pure function:函数的返回结果只依赖于它的参数;函数执行过程里面没有副作用),不能在里面执行this.setState,会有改变组件状态的副作用。

componentDidMount:

组件挂载到DOM后调用,且只会被调用一次

更新:

react组件更新方式主要包括props更新和state更新以及force update更新。

更新后的state和props相对之前无论是否有变化,都将引起子组件的重新render。

props更新生命周期钩子执行过程

componentWillReceiveProps(nextProps)

shouldComponentUpdate(nextProps, nextState)

componentWillUpdate(nextProps, nextState)

render

componentDidMount

state更新生命周期钩子执行过程

shouldComponentUpdate(nextProps, nextState)

componentWillUpdate(nextProps, nextState)

render

componentDidMount

forceupdate生命周期钩子执行

(forceUpdate()会导致组件跳过shouldComponentUpdate(),直接调用render(),但是不影响其子组件生命周期)

render

componentDidMount

卸载

componentWillUnmount

react16之后

react提出了fiber概念,如果要开启async rendering,在render函数之前的所有函数,都有可能被执行多次

所谓fiber,就是利用分片的思想,将一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。这一点优化在dom结构复杂且深的时候非常有用。

但是,正因为一次更新过程会分成多个分片完成,所以完全有可能一个更新任务还没有完成,就被另一个更高优先级的更新过程打断,这时候,优先级高的更新任务会优先处理完,而低优先级更新任务所做的工作则会全部作废,然后等待机会重头再来。

因为一个更新过程可能被打断,所以React Fiber一个更新过程被分为两个阶段(Phase):第一个阶段Reconciliation Phase和第二阶段Commit Phase。第一个阶段是可以被打断的,第二个阶段不可以。

第一个阶段包括:

  • componentWillMount

  • componentWillReceiveProps

  • shouldComponentUpdate

  • componentWillUpdate

第二阶段包括:

  • componentDidMount

  • componentDidUpdate

  • componentWillUnmount

React16之前,每个生命周期函数在一个加载或者更新过程中绝对只会被调用一次;但是在React Fiber中,不再是这样了,第一阶段中的生命周期函数在一次加载和更新过程中可能会被多次调用。

tips:阶段一有两颗树,Virtual DOM 树和 Fiber 树,Fiber 树是在 Virtual DOM 树的基础上通过额外信息生成的。它每生成一个新节点,就会将控制权还给浏览器,如果浏览器没有更高级别的任务要执行,则继续构建;反之则会丢弃 正在生成的 Fiber 树,等空闲的时候再重新执行一遍。

react16之后,除了shouldComponentUpdate,其他在render函数之前的所有函数(componentWillMount,componentWillReceiveProps,componentWillUpdate)都可以被静态函数getDerivedStateFromProps替代。而这三个生命周期钩子均加上了unsafe的前缀。

这个生命周期的功能实际上就是将传入的props映射到state上
getDerivedStateFromProps是一个静态函数,也就是这个函数不能通过this访问到class的属性,也并不推荐直接访问属性。而是应该通过参数提供的nextProps以及prevState来进行判断,根据新传入的props来映射到state。

该函数必须有返回值

当props传入的内容不需要影响state,就必须返回一个null,getDerivedStateFromProps本来(React v16.3中)是只在创建和更新(由父组件引发部分)中调用。如果不是由父组件引发,那么getDerivedStateFromProps也不会被调用,如自身setState引发或者forceUpdate引发。但是这样十分容易混淆,因此在16.4版本中,无论是Mounting还是Updating,也无论是因为什么引起的Updating,全部都会被调用。如图:

补充:

**getSnapshotBeforeUpdate()**被调用于render之后,可以读取但无法使用DOM的时候。它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。

参考

www.jianshu.com/p/514fe21b9…

www.jianshu.com/p/514fe21b9…

www.jianshu.com/p/ff32dea87…

zhuanlan.zhihu.com/p/26027085