注:本文描述的是基于 React 16 版本。

React 组件的生命周期

生命周期大体上可以分为以下几个部分:

  • 挂载
  • 更新
  • 卸载

每一个部分又细分为具体的钩子函数。

挂载

挂载 对应以下几个钩子函数:

  • constructor()
  • componentWillMount()
  • render()
  • componentDidMount()

componentWillMount() 已经被移除,原来的代码可以考虑迁移到 constructor()

以上钩子函数除了 render() 外,在组件首次挂载到 DOM 时执行一次,后续当组件的 props 和 state 更新时,不会再次执行。

在父子组件的情况下,constructor() 、 render() 的执行是由外至内的,即父组件依次全部执行后,接着子组件再依次全部执行。

而 componentDidMount() 则是由内到外的顺序。子组件先执行,接着父组件再执行。

完整的顺序如下:

父组件 constructor -> 父组件 render -> 子组件 constructor -> 子组件 render -> 子组件 componentDidMount -> 父组件 componentDidMount

更新

更新 对应以下几个钩子函数:

  • shouldComponentUpdate()
  • componentWillUpdate()
  • render()
  • componentDidUpdate()

componentWillUpdate() 已经被移除,原来的代码可以考虑迁移到 shouldComponentUpdate()

以上钩子函数在 props 和 state 每次变化时都会依次执行一遍。组件的第一次 挂载 ,不属于该情况,因此这部分钩子函数不会在组件首次挂载到 DOM 时执行。

另外,当父组件 更新 时,子组件也会无条件 更新 ,即使子组件的 props 和 state 没有变化。

在父子组件的情况下,更新 部分和 挂载 部分的钩子函数执行顺序有些相似。其中,shouldComponentUpdate() 、 render() 是从外至内的顺序,而 componentDidUpdate() 则是从内至外的顺序。

完整的顺序如下:

父组件 shouldComponentUpdate -> 父组件 render -> 子组件 shouldComponentUpdate -> 子组件 render -> 子组件 componentDidUpdate -> 父组件 componentDidUpdate

shouldComponentUpdate() 会根据返回值决定 更新 部分剩余的钩子函数是否执行,如果返回 True ,则表示组件应当更新。当没有定义该函数时,默认当做是返回 True 。

卸载

卸载 对应以下一个钩子函数:

  • componentWillUnmount()

当组件即将被卸载时,组件的 componentWillUnmount() 方法会执行。这样我们可以做一些 清理 操作,如取消定时器 clearTimeout() 、 clearInterval() ,取消 DOM 事件 removeEventListener() 、 detachEvent() , 取消自定义事件 removeListener() 。

注:在组件卸载时,确保组件相关的事件和定时器都已经移除,这样可以避免应用出现 内存泄漏 。