关于React v16.3 新生命周期

变动的部分

react v16.3终于出来了,最大的变更莫过于生命周期去掉了如下三个html

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

同时为了弥补失去上面三个周期的不足又加了两个前端

  • static getDerivedStateFromProps
  • getSnapshotBeforeUpdate

固然,这个更替是缓慢的,在整个16版本里都能无障碍的使用旧的三生命周期,但值得注意的是,旧的生命周期(unsafe)不能和新的生命周期同时出如今一个组件,不然会报错“你使用了一个不安全的生命周期”。react

为何要改

旧的生命周期十分完整,基本能够捕捉到组件更新的每个state/props/ref,没有什从逻辑上的毛病。安全

可是架不住官方本身搞事情,react打算在17版本推出新的Async Rendering,提出一种可被打断的生命周期,而能够被打断的阶段正是实际dom挂载以前的虚拟dom构建阶段,也就是要被去掉的三个生命周期。bash

生命周期一旦被打断,下次恢复的时候又会再跑一次以前的生命周期,所以componentWillMount,componentWillReceiveProps, componentWillUpdate都不能保证只在挂载/拿到props/状态变化的时候刷新一次了,因此这三个方法被标记为不安全。dom

两个新生命周期

static getDerivedStateFromProps

  • 触发时间(v16.4修正):组件每次被rerender的时候,包括在组件构建以后(render以前最后执行),每次获取新的props或state以后。在v16.3版本时,组件state的更新不会触发该生命周期。
  • 每次接收新的props以后都会返回一个对象做为新的state,返回null则说明不须要更新state.
  • 配合componentDidUpdate,能够覆盖componentWillReceiveProps的全部用法
class Example extends React.Component {
  static getDerivedStateFromProps(nextProps, prevState) {
    // 没错,这是一个static
  }
}
复制代码

getSnapshotBeforeUpdate

  • 触发时间: update发生的时候,在render以后,在组件dom渲染以前。
  • 返回一个值,做为componentDidUpdate的第三个参数。
  • 配合componentDidUpdate, 能够覆盖componentWillUpdate的全部用法。
class Example extends React.Component {
  getSnapshotBeforeUpdate(prevProps, prevState) {
    // ...
  }
}
复制代码

建议用法总结

  1. 初始化state — Initializing state异步

    • 在constructor初始化state就能够了
  2. 请求数据 — Fetching external dataasync

    • 在componentDidMount请求异步加载的数据
    • 有一种错觉,在componentWillMount请求的数据在render就能拿到,但其实render在willMount以后几乎是立刻就被调用,根本等不到数据回来,一样须要render一次“加载中”的空数据状态,因此在didMount去取数据几乎不会产生影响。
  3. 添加事件监听 — Adding event listeners (or subscriptions)ide

    • 在componentDidMount中添加加事件监听
    • react只能保证componentDidMount-componentWillUnmount成对出现,componentWillMount能够被打断或调用屡次,所以没法保证事件监听能在unmount的时候被成功卸载,可能会引发内存泄露
  4. 根据props更新state — Updating state based on props性能

    • 用getDerivedStateFromProps(nextProps, prevState), 将传入的props更新到state上
    • 用来代替componentWillReceiveProps(nextProps, nextState),willReceiveProps常常被误用,致使了一些问题,所以该方法将不被推荐使用。
    • getDerivedStateFromProps是一个static方法,意味着拿不到实例的this,因此想要在setState以前比对一下props有没有更新,下面方法是不能用了
    if (this.props.currentRow !== nextProps.currentRow) {
     	...
     }
    复制代码

    取而代之的是,额外写一个state来记录上一个props (` ^ ‘)

    if (nextProps.currentRow !== prevState.lastRow) {
      return {
        ...
        lastRow: nextProps.currentRow,
      };
      // 不更新state
      return null
    }
    复制代码
    • 为何咱们不给一个prevProps参数呢,官方解释是,一来prevProps第一次被调用的时候是null,每次更新都要判断耗性能,二来若是你们都习惯了,之后react不记录prevProps的话(啥),能够省下很多内存
  5. 触发请求 — Invoking external callbacks

    • 在生命周期中因为state的变化触发请求,在componentDidUpdate中进行
    • 为何不在componentWillUpdate中的理由同上2
  6. props更新引发的反作用 — Side effects on props change

    • props更改引起的可视变化(反作用,好比log,ga),在componentDidUpdate中处理
    // 在didUpdate中根据props更新的确很不适应
    // props变了也是能够触发update的
    componentDidUpdate(prevProps, prevState) {
    	if (this.props.isVisible !== prevProps.isVisible) {
    	  logVisibleChange(this.props.isVisible);
    	}
    }
    复制代码
    • componentWillUpdate, componentWillReceiveProps在一次更新中可能会被触发屡次,所以这种只但愿触发一次的反作用应该放在保证只触发一次的componentDidUpdate中。
  7. props更新时从新请求 — Fetching external data when props change

    • 传入新的props时从新异步取数据,getDerivedStateFromProps+ componentDidUpdate 替代 componentWillReceiveProps
    // old
      componentWillReceiveProps(nextProps) {
        if (nextProps.id !== this.props.id) {
        	this.setState({externalData: null});
          this._loadAsyncData(nextProps.id);
        }
      }
    复制代码
    // new
      static getDerivedStateFromProps(nextProps, prevState) {
        // Store prevId in state so we can compare when props change.
        if (nextProps.id !== prevState.prevId) {
          return {
            externalData: null,
            prevId: nextProps.id,
          };
        }
        // No state update necessary
        return null;
      }
      componentDidUpdate(prevProps, prevState) {
        if (this.state.externalData === null) {
          this._loadAsyncData(this.props.id);
        }
      }
    复制代码
  8. 在更新前记录原来的dom节点属性 — Reading DOM properties before an update

    • 在upate以前获取dom节点,getSnapshotBeforeUpdate(prevProps, prevState)代替componentWillUpdate(nextProps, nextState)
    • getSnapshotBeforeUpdate在render以后,但在节点挂载前
    • componentDidUpdate(prevProps, prevState, snapshot)直接得到getSnapshotBeforeUpdate返回的dom属性值

生命周期功能替换一览

static getDerivedStateFromProps(nextProps, prevState) {
    4. Updating state based on props
    7. Fetching external data when props change // Clear out previously-loaded data so we dont render stale stuff
  }
  constructor() {
	1. Initializing state
  }
  componentWillMount() {
  	// 1. Initializing state
  	// 2. Fetching external data
  	// 3. Adding event listeners (or subscriptions)
  }
  componentDidMount() {
	2. Fetching external data
	3. Adding event listeners (or subscriptions)
  }
  componentWillReceiveProps() {
  	// 4. Updating state based on props
  	// 6. Side effects on props change
  	// 7. Fetching external data when props change
  }
  shouldComponentUpdate() {
  }
  componentWillUpdate(nextProps, nextState) {
  	// 5. Invoking external callbacks
  	// 8. Reading DOM properties before an update
  	
  }
  render() {
  }
  getSnapshotBeforeUpdate(prevProps, prevState) {
	8. Reading DOM properties before an update
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
	5. Invoking external callbacks
	6. Side effects on props change
  }
  
  componentWillUnmount() {
  }

复制代码

最后

上面的内容基本就是结合个人一些经验半翻译半总结,有不许确的地方欢迎指正。

对更多细节感兴趣的话能够去看官方文档,https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html

对async-rendering或者对dan小哥哥感兴趣的话能够去看看他在前端大会上的一段小演示:https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html

相关文章
相关标签/搜索