React 15

Ciqc1F-GZbGAGNcBAAE775qohj8453.png

  • componentReceiveProps 并不是由 props 的变化触发的,而是由父组件的更新触发的

    React 16

    Ciqc1F-FVcSALRwNAAIomWwVcQU231.png

    Mounting 阶段:组件的初始化渲染(挂载)

    Ciqc1F-Klv6AIeOPAADAZZgLu7U105.png

  • getDerivedStateFromProps:使用 props 来派生、更新 state

    • 被定义为 static,方法内部拿不到组件实例的 this
    • 返回值必须是对象或 null
  • render 函数每次渲染时都会被调用,如果存在 setState 会触发渲染,造成死循环

    1. // 初始化/更新时调用
    2. static getDerivedStateFromProps(props, state) {
    3. console.log("getDerivedStateFromProps方法执行");
    4. // 使得本组件的 state 具有或更新 fatherText 的值为 props.text
    5. return {
    6. fatherText: props.text
    7. }
    8. }

    Updating 阶段:组件的更新

    CgqCHl-KlxyAB5MpAAFaH-Kgggo887.png

  • 用 getDerivedStateFromProps 代替 componentWillReceiveProps

    • 强制推行“只用 getDerivedStateFromProps 来完成 props 到 state 的映射”这一最佳实践
    • 确保生命周期函数的行为更加可控可预测
  • 使用 getSnapshotBeforeUpdate 取代 componentWillUpdate
    • 返回值会作为第三个参数给到 componentDidUpdate
    • 此阶段可以同时获取到更新前的真实 DOM 和更新前后的 state & props 信息 ```typescript getSnapshotBeforeUpdate(prevProps, prevState) { // Are we adding new items to the list? // Capture the scroll position so we can adjust scroll later. if (prevProps.list.length < this.props.list.length) { const list = this.listRef.current; return list.scrollHeight - list.scrollTop; } return null; }

componentDidUpdate(prevProps, prevState, snapshot) { // If we have a snapshot value, we’ve just added new items. // Adjust scroll so these new items don’t push the old ones out of view. // (snapshot here is the value returned from getSnapshotBeforeUpdate) if (snapshot !== null) { const list = this.listRef.current; list.scrollTop = list.scrollHeight - snapshot; } ```

生命周期更改的原因

React 16 改造生命周期的主要动机是为了配合 Fiber 架构带来的异步渲染机制 render 阶段在执行过程中允许被打断,而 commit 阶段则总是同步执行的

在 Fiber 机制下,render 阶段是允许暂停、终止和重启的。当一个任务执行到一半被打断后,下一次渲染线程抢回主动权时,这个任务被重启的形式是“重复执行一遍整个任务”而非“接着上次执行到的那行代码往下走”。这就导致 render 阶段的生命周期都是有可能被重复执行的
React 16 打算废弃的是哪些生命周期:

  • componentWillMount;
  • componentWillUpdate;
  • componentWillReceiveProps。

这些生命周期的共性,就是它们都处于 render 阶段,都可能重复被执行,而且由于这些 API 常年被滥用,它们在重复执行的过程中都存在着不可小觑的风险。

参考资料

  1. 02 | 为什么 React 16 要更改组件的生命周期?(上)
  2. 03 | 如何避免生命周期中的坑?