注:本文描述的是基于 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() 。
注:在组件卸载时,确保组件相关的事件和定时器都已经移除,这样可以避免应用出现 内存泄漏 。