目录标题
“如何避免坑?”换种思维思考也就是“为什么会有坑?”在代码编写中,遇到的坑往往会有两种:
- 在不恰当的时机调用了不合适的代码
- 在需要调用的时候,没有调用
要避免生命周期的坑,就需要先了解React有那些生命周期?在React的不同版本生命周期的钩子函数也大同小异。React的生命周期分为三个挂载、更新、销毁阶段,不同的阶段触发不用的钩子函数。接下来我们就一一来看看。
组件的初始化渲染(挂载)
constructor
constructor是类的构造函数,在组件初始化的时候只会执行一次,用于初始化state和绑定函数。
但是随着类属性的流行,我在很多的代码中看到不在写constructor,而是改用类属性。移除constructor的原因无非就是:
- 让代码变得更加简洁
- constructor并不是React生命周期的一部分
componentWillMount
该方法也是也是在挂载的时候调用一次,并且方法在render方法之前调用。该方法在React后期的版本就已经标记废弃。原因是在React异步机制下,该生命周期钩子可能会被多次调用。最直观的一个例子,在该方法中写了异步请求,那有可能会被多次触发。
render
render方法并不会去真正的操作DOM,它的作用是把需要的东西返回回来。真正渲染的工作,是挂载阶段的ReactDOM.render方法去操作。
componentDidMount
componentDidMount方法执行,意味着初始化挂载的操作基本完成。它主要用于组件加载完成时做某些操作,比如发起网络请求、绑定事件或者你已经可以对DOM进行操作了,该函数是接着 render 之后调用的。但 componentDidMount 一定是在真实 DOM 绘制完成之后调用吗?在浏览器端,我们可以这么认为。
但在其他场景下,尤其是 React Native 场景下,componentDidMount 并不意味着真实的界面已绘制完毕。由于机器的性能所限,视图可能还在绘制中。
组件更新阶段
componentWillReceiveProps
该方法在后续的版本已经标记弃用,被getDerivedStateFromProps方法替代。在早起的版本这个方法还是有用的,有用的原因是在很多人其实并没有很明白这个方法到底由什么触发:
- 当父组件修改传递给子组件的属性时,这个修改会带动子组件的对于属性的修改,触发componentWillReceiveProps生命周期。
- 当父组件触发了个子组件无关的属性也会触发子组件的componentWillReceiveProps,这说明componentWillReceiveProps方法的触发不一定都是由于父组件传递给子组件的属性改变而引入的。
shouldComponentUpdate
在更新的过程中,会触发render方法来生成新的虚拟DOM,进行diff找出需要修改的DOM。这个过程是很耗费时间的。在实际操作中,我们会无意触发render方法,为了避免不必要的render调用带来的性能消耗,所以React让我们可以在shouldComponent方法决定是否要执行余下的声明周期,默认它是返回true。我们也可以手动设置false,不进行余下的生命周期。
componentWillUpdate
在render函数之前执行,运行做一些不涉及真实DOM的操作。后续版本已经被废弃。
render
和挂载阶段一致
componentDidUpdate
在render函数之后执行,DOM已经更新完成。这个生命周期也经常被用来处理 DOM 操作。此外,我们也常常将 componentDidUpdate 的执行作为子组件更新完毕的标志通知到父组件。
组件销毁
componentWillUnmount
组件卸载之前触发的生命周期,该函数主要用于执行清理工作。一个比较常见的 Bug 就是忘记在 componentWillUnmount 中取消定时器,导致定时操作依然在组件销毁后不停地执行。所以一定要在该阶段解除事件绑定,取消定时器。在平时写代码的时候如果不解除事件绑定和定时器可能会带来意向不想的问题。
componentWillUnmount会在两种情况下触发
- 组件在父组件中被移除(销毁)
- 组件设置了KEY属性,父组件在re-render的时候发现key和上一次不一致了就会被移除
react 15 和 react 16
组件的初始化渲染(挂载)
消失的 componentWillMount,新增的 getDerivedStateFromProps。
注意这个的getDerivedSatateFromProps不是componentWillMount的替代品
。getRerivedSatateFromProps设计的初衷是为了替代componentWillReceiveProps
- getDerivedStateFromProps是一个静态方法,不依赖实例存储,所以在getDerivedStateFromProps方法内是访问不到this的。
- getDerivedStateFromProps接受两个参数,第一个参数是接受来自父组件的props,第二参数是当前组件自生的state。
- getDerivedStateFromProps需要一个对象格式的返回值,如果你没有返回值,React会发出警告。
- getReriverSatateFromProps的返回值之所以不可或缺,是因为React需要使用这个返回值来更新组件的state。因此当你确实不存在“使用 props 派生state”这个需求的时候,最好是直接省略掉这个生命周期方法的编写,否则一定记得给它 return 一个 null。
- 注意getDerivedStateFromProps对state的更新动作不是覆盖式,是针对性的更新。