React 生命周期及相关用法
-
创建阶段
componentWillMount():实例挂载之前
render()
componentDidMount():实例挂载完成。一般在这个函数中与后台进行初始化数据交互 -
运行更新阶段
componentWillReceiveProps(nextProps):父组件改变时调用。
shouldComponentUpdate(nextProps, nextState):主要是用来手动阻止组件渲染,一般在这个函数中做组件的性能优化。
componentWillUpdate(nextProps, nextState):组件数据更新前调用
render()
componentDidUpdate(prevProps, prevState):组件数据更新完成时调用
render(): 渲染组件 -
卸载阶段
componentWillUnmount():销毁阶段。一般用来销毁不用的变量或者是解除无用定时器以及解绑无用事件。防止内存泄漏问题 -
react 新增生命周期
getDerivedStateFromProps(nextProps, prevState)
getSnapShotBeforeUpdate(prevProps, prevState)
阶段详解
- constructor
constructor 中完成了 react 数据的初始化,他接收两个参数: props 和 context,当想在函数内部使用这两个参数时,需要使用 super() 传入这两个参数
constructor(props, context) {
super(props, context)
}
注:只要使用了 constructor() 就必须写 super() 否则会导致 this 的指向错误。
-
componentWillMount()
在服务渲染时使用,代表组件经历了 constructor() 初始化数据后,但是还未渲染 DOM 树 -
componentDidMount()
组件第一次渲染完成,此时 DOM 节点已经生成,可以在这里调用 ajax 请求,返回数据 setState 后组件会重新渲染 -
componentWillReceiveProps (nextProps)
1.在接受父组件改变后的 props 需要重新渲染得时候用到
2.接受一个参数 nextProps
3.通过对比 nextProps 和 this.props 将 nextProps 的 state 更新当前 state 从而重新渲染组件
componentWillReceiveProps(nextPorps) {
nextPorps.matchIndex !== this.state.matchIndex && this.setState({
matchIndex: nextPorps.matchIndex
}, () => {
console.log(this.state.matchIndex:nextPorps)
})
}
-
shouldComponentUpdate(nextProps, nextState)
1.主要用于性能优化 ( 部分更新 )
2.唯一用于控制组件重新渲染的生命周期,由于在 react 中 setState 后 state 发生变化,组件会进入重新渲染的流程,在这里 return false 可以阻止组件的更新
3.因为 react 父组件的重新渲染会导致其所有子组件的重新渲染,这个时候其实我们是不需要所有子组件都跟着重新渲染的,因此需要在子组件的该生命周期中做判断 -
componentWillUpdate (nextProps, nextState)
shouldComponentUpdate 返回 true 后,组件进入重新渲染的流程,进入 componentWillUpdate,这里同样能拿到 nextProps 和 nextState -
componentDidUpdate(prevProps, prevState)
组件更新完毕后,react 只会在第一次初始化成功进入 componentDidMount,之后每次重新渲染都会进入这个生命周期,这里可以拿到 PrevProps 和 prevState,即更新前的 props 和 state -
render()
render 函数会插入 jsx 生成的 dom 结构,react 会生成一份虚拟 dom 树,在每一次组件更新时,react 会通过其 diff 算法比较更新前后新旧 DOM 树,比较以后找到最小的有差异的 DOM 节点,并重新渲染 -
componentWillUnmount ()
在此处完成组件的卸载和数据的销毁
1.clear 组件中的所有 setTimeout 和 setInterval
2.移除所有组件中的监听removeEventListener
3.有时候会碰到一个 warning: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.isMount = true
axios.post().then((res) => {
this.isMount && this.setState({
xxx: res
})
})
}
componentWillUnMount() {
this.isMount = false
}
- getDerivedStateFromProps(nextProps, prevState)
代替 componentWillReceiveProps()
老版本中的 componentWillReceiveProps() 方法判断前后两个 props 是否相同,如果不同再将新的 props 更新到 state 上去,这样做来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。
// before
componentWillReceiveProps(nextProps) {
if(nextProps.isLogin !== this.props.isLogin) {
this.setState({
isLogin: nextProps.isLogin
})
}
if(nextProps.isLogin) {
this.handleClose()
}
}
// after
static getDerivedStateFromProps(nextProps, prevState) {
if(nextProps.isLogin !== prevState.isLogin) {
return {
isLogin: nextProps.isLogin
}
}
return null
}
componentDidUpdate(prevProps, prevState) {
if(!prevState.isLogin && this.props.isLogin) {
this.handleClose()
}
}
两者最大的不同:
在 componentWillReceiveProps 中我们做两件事:
1.根据 props 来更新 state
2.触发一些回调,比如动画或者页面跳转等。
而在新版本中:
1.官方将更新 state 与触发回调重新分配到了 getDerivedStateFromProps 与 componentDidUpdate 中,使得组件整体的更新逻辑更加清晰。
2.在 getDerivedStateFromProps 中还禁止了组件去访问 this.props,强制让开发者去比较 nextProps 和 prevState 中的值,以确保当前开发者用到 getDerivedStateFromProps 这个函数的时候就是根据当前的 props 来更新组件的 state,而不是去做一些其它让组件自身状态变的不可预测的事情。
- getSnapshotBeforeUpdate(prevProps, prevState)
代替 componentWillUpdate
常见的 componentWillUpdate 是在组件更新前,读取当前某个 DOM 的状态,并在 componentDidUpdate 中进行相应的处理
两者的区别:
1.在 React 开启异步渲染模式后,在 render 阶段读取到的 DOM 状态并不总是和 commit 阶段相同,这就导致在 componentDidUpdate 中使用 componentWillUpdate 中读取到的 DOM 元素状态是不安全的,因为这时候的值很有可能已经失效了
2.getSnapShotBeforeUpdate 会在最终的 render 之前调用,也就是说在 getSnapShotBeforeUpdate 中读取到的 DOM 元素状态是可以保证与 componentDidUpdate 中一致的,此生命周期返回的任何值都将作为参数传递给 componentDidUpdate()