关于react的新生命周期
2019-04-20 本文已影响0人
王小滚
在react中旧的生命周期其实已经十分完整,基本可以捕捉到组件更新的每一个state/props/ref,没有什从逻辑上的毛病。
1. 旧的生命周期
旧的生命周期当然我们现在,在整个16版本里都能无障碍的使用旧的三生命周期,但旧的生命周期(unsafe)不能和新的生命周期同时出现在一个组件,否则会报错。
可以看出三个即将被删除的生命周期,都是在实际dom挂载之前的虚拟dom构建阶段。这也正是react打算在17版本推出新的Async Rendering,提出一种可被打断的生命周期,而可以被打断的正是即将要被去掉的三个生命周期。生命周期一旦被打断,下次恢复的时候又会再跑一次之前的生命周期了。
2. 新的生命周期
接下来我们看下新增的生命周期:
static getDerivedStateFromProps
- 触发时间:挂载组件时,该静态方法会在render前执行;更新组件时,该静态方法会在shouldComponentUpdate前执行。
- 每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state.
-
getDerivedStateFromProps
是一个静态方法,是拿不到实例this的,所以开发者应该将该函数设计成纯函数。 -
getDerivedStateFromProps
中还禁止了组件去访问this.props
,强制让开发者去比较nextProps
与prevState
中的值,以确保当开发者用到getDerivedStateFromProps
这个生命周期函数时,就是在根据当前的props
来更新组件的 state,而不是去做其他一些让组件自身状态变得更加不可预测的事情。
乍看下来 static getDerivedStateFromProps
和即将被删掉componentWillReceiveProps
这二者好像并没有什么本质上的区别,但这却是这其实是最能够体现 React 团队对于软件工程深刻理解的一个改动,即 React 团队试图通过框架级别的 API 来约束或者说帮助开发者写出可维护性更佳的 JavaScript 代码。
class test extends Component {
// before
componentWillReceiveProps(nextProps) {
if (nextProps.isSupportCaps !== this.props.isSupportCaps) {
this.setState({
isSupportCaps: nextProps.isSupportCaps,
});
}
if (nextProps.isSupportCaps) {
this.handleCaps();
}
}
// after
static getDerivedStateFromProps (nextProps, prevState) {
if (nextProps.isSupportCaps !== prevState.isSupportCaps) {
return {
isSupportCaps: nextProps.isSupportCaps,
};
}
return null;
}
componentDidUpdate(prevProps, prevState) {
if (!prevState.isSupportCaps && this.props.isSupportCaps) {
this.handleCaps();
}
}
}
在新版本中,官方将更新 state
与触发回调重新分配到了 getDerivedStateFromProps
与 componentDidUpdate
中,使得组件整体的更新逻辑更为清晰。
getSnapshotBeforeUpdate
- 触发时间: update发生的时候,在render之后,在组件dom渲染之前。
- 返回一个值,作为componentDidUpdate的第三个参数。
- 配合componentDidUpdate, 可以覆盖componentWillUpdate的所有用法。
官方提供的一个例子如下:
class ScrollingList extends React.Component {
listRef = null;
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
return (
this.listRef.scrollHeight - this.listRef.scrollTop
);
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
if (snapshot !== null) {
this.listRef.scrollTop =
this.listRef.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.setListRef}>
{/* ...contents... */}
</div>
);
}
setListRef = ref => {
this.listRef = ref;
};
}
getSnapshotBeforeUpdate
的使用场景一般是获取组建更新之前的滚动条位置。