三个生命周期方法在整个声明周期中的位置:

微信截图_20181112235838.png

一、componentDidMount

react 文档中有建议将网络请求放在 componentDidMount 而不是放在 componentWllMount 中,文档的阐述是说只有放在 componentDidMount 中,才能当数据拿到之后,调用 setState 去更新组件,但其实在 componentWillMount 中进行异步操作,也能进行 setState。(有另一种解释,reactv16中使用了 fiber 架构,只有 componentDidMount 能够保证只执行一次,componentWillMount 无法保证):

这里主要是对 componentDidMount 的文档上的再次理解。

componentDidMount 的作用时机实际上在讲组件(插入树中)之后立即调用,如果需要对 DOM 节点进行初始化,应该在这里进行操作。同样的,如果需要在远程节点请求数据,也应该在 componentDidMount 中进行。

文档中也推荐 componentDidMount 中进行 subscription,比如 setTimeout 这种,当然需要在 componentWillMount 中销毁。

在 componentDidMount 中是能够立即进行 setState 的(这里的立即进行 setState 是指给 state 执行初始值的操作,而不是网络请求),这个过程是发生在浏览器更新前, 会触发一次额外的 render(),如果此时你在 render 中输出内容,会多输出一次。虽然会多触发一次 render,但其实用户是看不到的中间状态的。但是这种模式并不应当使用,会导致性能问题,如果要初始化 state, 应当在 constructor 中进行。当然,如果需要显示 modal 或者是 tooltip 这种提示型的组件,并且位置需要依赖 DOM,也可以在 componentDidMount 中进行处理。

二、componentDidUpdate

componentDidUpdate(prevProps, prevState, snapshot) 在组件发生更新之后会立即被调用,但是在初始化的时候是不会被调用的。

因此在 componentDidUpdate 中可以在组件更新的时候,对 DOM 进行一些操作,同时这个方法有三个参数,可以通过参数比较比如 props ,能够判断是否需要网络请求新的数据等,比如官方文档给的示例如下:

componentDidUpdate(prevProps) {
  // Typical usage (don't forget to compare props):
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
}

如果你在 componentDidUpdate中立即执行setState,需要额外注意的是你可能引入了死循环,这是因此每次 setState 都会执行到 componentDidUpdate,然后又进行 setState,从而导致整个应用挂掉。如果真的需要 setState,是必须放在条件中的,比如上面的示例代码中,由条件的决定,则不会引发死循环问题。

当然,这种做法也可能会导致重复的进行 render,虽然用户看不见,但是非常影响组建的性能

如果你进行了 state的派生操作 很可能会引发一系列的问题,导致应用无法按照预期执行。更多关于派生 state 的问题,官方博客见:

之后会将这篇文章翻译一下,深度的理解。

注意:

如果 shouldComponentUpdate 返回了 false, componentDidUpdate 是一定不会被执行的

三、componentWillUnmount

react 在卸载和销毁组件之前会立即调用 componentWillUnmount 方法, 如果使用计时器比如 setTimeout,可以在此时进行销毁。

初次之外可以在该方法中取消网络请求,或者是清楚 componentDidMount 中的一些监听订阅行为。

componentWillUnmount 中是不能进行 setState,因为组件已经被销毁了,所以永远不会在去重新 render。