一、说明

react 的发展过程中算是比较稳健的,并没有大跨越扯着蛋的行为,(虽然现在我觉得有点激进了),而 React.Component 中生命周期方法目前也处于一个过渡期,因为有几个方法即将被放弃。

这几个生命周期方法是 legacy (遗留)的,不过在现在的版本中依旧能够使用,但是在 React V17 中可能会直接被移除。而关于遗留生命周期的方法 React 也有一篇博客:

二、UNSAFE_componentWillMount

UNSAFE_componentWillMount 其实就是 componentWillMount,我最早使用 react 的时候还是蛮喜欢用这个方法的,甚至数据请求也放在这个方法中,这个方法是在组件 mount 之前进行调用,也就是在 render() 之前,因此在方法中同步调用 setState 是不会触发额外的一次渲染的。

目前 React 是强烈建议在 constructor 中初始化状态的,如果有在 componentWillMount 中进行 state 的初始化,是绝对不推荐的

同样的,不应该在 componentWillMount 中使用任何副作用方法或者产生 subscriptions(订阅),对于这些情况,应当使用 componentDidMount 来替代。

componentWillMount 是唯一一个服务端渲染的时候调用的生命周期方法。

注意事项

虽然标题写的是 UNSAFE_componentWillMount, 但实际上之前的名字 componentWillMount 还是能够继续使用的,不过在 react 17 中,可以使用 react 提供的脚本:https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles 来自动更新组件。

三、UNSAFE_componentWillReceiveProps

componentWillReceiveProps 这个方法我基本上没用过,稳定性太差,很多时候 bug 都不知道为什么来的,因此在之后的 react 版本中,这个方法也会被废弃掉。

如果需要执行副作用(数据获取、动画等)来响应 props 的变动,可以直接使用 componentDidUpdate 生命周期,而其他的一些情况,react 的博客中有一篇关于派生 state 的文章:https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html

如果在 props 的变动的时候之前使用 componentWillReceiveProps 重新计算某些数据,现在是推荐使用记忆话的方式(memoization)去实现。而 memoization 的具体实现可以使用 memoize-one: https://npm.taobao.org/package/memoize-one

如果是在 props 发生变动的时候在 componentWillReceiveProps 中重置某些状态,应该考虑使用完全可控组件或者是带 key 的完全不可控组件。不过在极少数的情况下,可能会使用 getDerivedStateFromProps 生命周期方法作为最后的解决方法。

componentWillReceiveProps 是在挂载组件之后,每次接收到新的 props 之前就调用了,如果需要更新 state 来响应 prop 更改(比如重置),可以通过比较 this.props 和 nextProps 然后在这个方法中调用 this.setState 来进行状态变更。

需要注意的是,如果父组件的 re-render 引起的组件 render,即使没有变更 props,componentWillReceiveProps 也会触发该方法。这就导致,如果你需要当且只当 props 变更的时候才进行一些操作,就必须要对 this.props 和 nextProps 进行比较。

在 mounting 的时候,也就是第一次 props 传入的时候,React 是不会调用 componentWillReceiveProps 方法的。如果某些组件的 props 发生了更新,会调用这个生命周期,但是 this.setState 是不会触发 componentWillReceiveProps的。

注意:

同样的,componentWillReceiveProps 方法依旧是这个名字,只不过为了表示是 legacy 的,因此强调了 UNSAFE,如果之后 react 17 出现,则需要通过 rename-unsafe-lifecycles codemod 进行组件的自动更新。

四、UNSAFE_componentWillUpdate

componentWillUpdate(nextProps, nextState) 方法是在接收到新的 props 或者是 state 时候,将要 render 前调用的,使用这个方法在 render 之前执行更新前的一些操作,只是在初始化的时候,这个方法是不会被调用的。

需要注意的是,绝对不能再 componentWillUpdate 里面进行 this.State({}), 这应该会直接触发类似死循环的栈溢出行为,同时,也不能在 componentWillUpdate 中进行任何其他的操作,比如:调用 redux 来触发 react 组件的更新,原因是一样的。

一般来说,componentWillUpdate 可以使用 componentDidUpdate 类替换。如果在这个方法中有使用 DOM 的情况(比如保存滚动的位置),可以把这个逻辑移动到 getSnapshotBeforeUpdate

注意:

同样的,和其他几个方法一样,componentWillUpdate方法依旧是这个名字,只不过为了表示是 legacy 的,因此强调了 UNSAFE,如果之后 react 17 出现,则需要通过 rename-unsafe-lifecycles codemod 进行组件的自动更新。

当然,如果 shouldComponentUpdate 中返回了 false,componentWillMount 是不会被调用的。