大家在写React代码的时候也就是在React的生命周期函数中编写代码,有的时候我们在两个生命周期中编写代码可能得到的是相同的结果,但是对于生命周期的使用是有最佳实践的。
特别是在React v16.3之后引入了异步渲染的概念,这个时候我们如何使用生命周期就变得更加重要了,首先我们先来看看v16.3之前的生命周期
React v16.3以前的生命周期
创建阶段
1 | // 构造函数 |
构造函数阶段,只调用一次,接收到传入的props,需要手动调用super(props)
在这个阶段我们对组件的state数据进行初始化
1 | render() { |
render阶段 这个阶段我们渲染UI1
2
3
4
5
6
7componentDidMount() {
const container = this.DomContainer
const containerHeight = container.clientHeight
this.setState({
containerHeight
})
}
UI渲染完毕的阶段,只调用一次,在这个生命周期开始DOM才被创建,一些jquery库需要在这里初始化,如果需要计算DOM的高度来初始化,那么也应该在这里进行初始化
更新阶段
更新分为两种:一种是父组件传入的props变化,或者组件调用setState()
当props发生变化时进入1
2componentWillReceiveProps(nextProps) {
}
在这里我们可以更新组件的state,但是最好是根据组件的props计算后去渲染UI,因为这样可以保证单一数据源又避免维护一份数据产生额外的开销
1 | shouldComponentUpdate(nextProps, nextState) { |
返回一个boolean值,表示是否应该更新,默认返回true,返回false时不再执行下面的生命周期
1 | componentWillUpdate(nextProps, nextState) { |
render声明周期前后分别是componentWillUpdate和componentDIdUpdate
更新的第二种是组件调用forceUpdate,这时候会直接进入componentWillUpdate
卸载阶段
1 | componentWillUnmount() { |
组件在页面卸载之前进入componentWillUnmount生命周期,在这里我们可以对需要清理的资源资源进行释放,比如:清除计时器
Reactv16.3开始的生命周期
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
这些生命周期方法经常被错误的使用,当开启异步渲染的时候可能存在安全隐患
所以16.3版本开始 这些生命周期将增加UNSAFE_开头的别名
17.0版本开始将删除这些生命周期 只有UNSAFE_开头的生命周期可以使用
新增俩个生命周期getDerivedStateFromProps和getSnapshotBeforeUpdate
1 | getDerivedStateFromProps(nextProps, prevState) { |
这个生命周期替换了componentWillReceiveProps的所有情况,接收到nextProps和prevState,返回一个state对象merge到原来的state
1 | getSnapshotBeforeUpdate(prevProps, prevState) { |
这个生命周期替换了componentWillUpdate,返回的对象将作为第三个参数传给componentDidUpdate
除了这俩个生命周期的变化,还提出了三个阶段的概念,render阶段,pre-commit阶段和commit阶段,由于要支持异步渲染,所以组件的生命周期可能由于优先级更高的事件触发而终止,
在render阶段我们可以终止组件继续渲染。
在pre-commit阶段我们可以对dom的数据进行读取。
在commit阶段我们可以使用dom,执行副作用操作。
- 添加事件监听
componentWillMount 和 componentWillUnmount 不是一对生命周期
只有调用了componentDidMount 才一定会调用 componentWillUnmount
所以如果在componentWillMount中做了一些比如注册监听的工作
由于component 在没有完成componentDidMount的时候可能会被打断
所以也不会执行 componentWillUnmount 中的清理工作 It can leak
所以我们应该把注册监听的操作放到componentDidMount中执行
这样就保证我们在componentWillUnmount中的清理工作一定会被执行 获取外部数据
在componentWillMount中大家可能会去获取外部数据
使得数据会再componentDIdMount的时候正确的渲染
但实际上这是做不到的
在执行完componentWillMount之后会立刻执行componentDidMount
这是一个同步执行的过程 而从接口获取数据是一个异步的过程
所以提前到componentWillMount中执行是没有意义的初始化数据
componentWillMount 中初始化数据的操作应该迁移到constructor中componentWIllUpdate 和 componentDidUpdate
当组件更新时需要产生副作用 使用componentDidUpdate 而不是componentWillUpdate
在异步模式下 多次willUpdate可能只会触发一次真正的更新所以在willUpdate中产生副作用可能达不到你想要的预期getSnapshotBeforeUpdate(prevProps, prevState)
使用componentWillUpdate读取dom属性对于异步渲染来说
componentWillUpdate 和 render 属于 render 生命周期
与 componentDidUpdate 之间存在延迟
如果在这个时间内用户改变了dom 存储的数据将会失效
解决的方法就是使用getSnapshotBeforeUpdate方法