react生命周期有三个阶段,挂载期,运行期,卸载期
1,挂载期
constructor()
componentWillMount()
componentDidMount()
2,卸载期
componentWillUnmount()
3,更新期
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()
4,新增的生命周期
getDerviedStateFromProps()
getSnapshotBeforeUpdate()
1,挂载期
1.1,constructor()
在constructor()内完成初始化数据,constructor接受两个参数props,context,如果想在函数内部使用这两个参数,需要使用super()来继承
1.2,componentWillMount()
此生命周期用放入比较少,更多的是用在服务端,componentWillMount发生在render函数之前,此时dom还没挂在,如果在此生命周期中进行setState,无意义的进行一次不知道要挂载在哪里的操作
1.2,componentDidMount()
组件的第一次渲染已经完成,dom节点已经生成,数据请求可以在此生命周期进行
2,卸载期
2.1 componentWillUnmount()
在此生命周期进行数据的销毁和组件的卸载:
(1)清楚所有的定时器setTimeout()和setInterval()
(2) 移除事件监听addeventListener
特别说明:
有时在componentWillUnmount()进行卸载时,会报:
Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the undefined component.
这是因为组件中ajax请求时会进行setState,因为请求还没完成就进行了卸载,解决办法
componentDidMount(){
this.mountIsGoing=true
fetch(url,{method:'POST'}).then((res)=>{
if(this.mountIsGoing){
this.setState({})
}
})
}
componentWillUnmount(){
this.mountIsGoing=false
}
3,更新期
3.1 componentWillReceiveProps(nextProps)
(1)接受父组件更新后的props进行组件重新渲染
(2)接受一个参数
(3)通过比较nextProps和this.props的值,将nextProps的state作为当前的state进行组件的重新渲染
componentWillReceiveProps(nextProps){
if(nextProps.index!==this.props.index){
this.setState({
index:nextProps.index
})
}
}
3.1 shouldComponentUpdate(nextProps,nextState)
(1)接受两个参数
(2)主要用于性能优化
(3)唯一一个可以控制组件是否需要重新渲染,在react中setState之后,state发生变化,会重新进行渲染,如果在这里return false将会阻止重新渲染。假如父组件里有多个子组件,当父组件的props发生变化时,导致所有的子组件都会进行更新,但有的子组件是不需要跟着更新,此时我们可以在子组件的此生命周期中进行组件更新
3.2 componentWillUpdate(nextProps,nextState)
组件在初始化渲染时不会调用此方法,当组件的shouldComponentUpdate返回true,接受到新的props和state会立刻调用,在此生命周期不能进行setState,因为setState被调用后,state发生改变则会重新渲染组件,组件每次更新都会调用componentWillUpdate,这样会造成死循环
3.3 componentDidUpdate(nextProps,nextState)
dom更新已经完成,可以在此生命周期进行dom操作
4,新增的生命周期
4.1 getDerivedStateFromProps(nextProps,nextState)
将代替componentWillReceiveProps,在componentWillReceiveProps通过对比两个props是否相同,如果不同再将新的props赋值给state,从而更新组件,这样做一来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。
例如:
componentWillReceiveProps(nextProps) {
if (nextProps.index !== this.props.index) { this.setState({
index: nextProps.index, });
}
if (nextProps.index) { this.updateCurrentIndex();
}
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.index !== prevState.index) { return {
index: nextProps.index, };
}
return null;
}
componentDidUpdate(prevProps, prevState) {
if (!prevState.index && this.props.index) { this.updateCurrentIndex(); }
}
由此可以看出,两者的区别在于:
(1)我们一般会在componentWillReceiveProps中通过新的props来更新state,或者是触发一些回调函数
(2)在getDerviedStateFromProps中,官方将更新 state 与触发回调重新分配到了 getDerivedStateFromProps 与 componentDidUpdate 中,使得组件整体的更新逻辑更为清晰。而且在 getDerivedStateFromProps 中还禁止了组件去访问 this.props,强制让开发者去比较 nextProps 与 prevState 中的值,以确保当开发者用到 getDerivedStateFromProps 这个生命周期函数时,就是在根据当前的 props 来更新组件的 state,而不是去做其他一些让组件自身状态变得更加不可预测的事情
4.2 getSnapshotBeforeUpdate(nextProps,nextState)
将代替componentWillUpdate
1,在 React 开启异步渲染模式后,在 render 阶段读取到的 DOM 元素状态并不总是和 commit 阶段相同,这就导致在componentDidUpdate 中使用 componentWillUpdate 中读取到的 DOM 元素状态是不安全的,因为这时的值很有可能已经失效了。
2,getSnapshotBeforeUpdate 会在最终的 render 之前被调用,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态是可以保证与 componentDidUpdate 中一致的。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。