该生命周期任何时候, state 的值都取决于 props ( Derived 意思为衍生的,英语好的同学看到名字就能知道这个生命周期的用法了吧)
static getDerivedStateFromProps(nextProps, state) {
return null;
}
此生命周期执行的时机在第一次初始化后,父组件重新渲染后,或者调用 setState() / forceUpdate() 后。该方法属于静态方法,无权访问 class 内部,也就是拿不到 this ,但是该回调函数的 return 返回值,将作为 state 与 组件内部 state 进行合并,若返回 null 则不更新 state 。
注意:
1. [email protected] 版本下 setState() 和 forceUpdate() 并不会进入该钩子函数。
2.这是一个非常规的生命周期,因为会派生新的state,导致数据来源多样,难以维护,应该考虑使用受控组件或者完全非受控组件来代替。
同理,英语好的同学看到标题应该就能明白用法了, Snapshot 意思为快照。具体用发需要配合 componentDidUpdate 一块使用。
getSnapshotBeforeUpdate() {
return 1;
}
componentDidUpdate(prevProps, prevState, snapshot) {
}
在真实 dom 和 ref 确认更新前进入该钩子函数,能在发生更改前从之前的 DOM 中获取一些信息,类似于上一次的 Dom 快照,返回值将作为参数传递给 componentDidUpdate , 常用于获取滚动位置等。
componentDidUpdate(prevProps, prevState, snapshot )
新增第三个参数接收来自 getSnapshotBeforeUpdate 的返回值。
componentWillMount / componentWillUpdate / componentWillReceiveProps
UNSAFE_componentWillMount
UNSAFE_componentWillUpdate
UNSAFE_componentWillReceiveProps
同步渲染过渡到异步渲染( React Fiber )
到目前为止, React 的渲染更新过程都是同步的,每一次加载或者更新树组件,都会做很多事,比如调用各个组件的生命周期,计算对于 Virtual Dom 最后更新 DOM 树,然而过多的操作,更深的层级容易导致这系列的执行时间过长,浏览器的主线程长期被占用,从而出现卡顿或者假死的现象。同步渲染过程如下:
为了解决同步操作时间过长的方法, React 计划在 17 版本启用最新的核心算法: React Fiber 从而实现异步渲染——大致原理是将一次更新过程变成多个分片完成,主要就是分为 Reconciliation Phase (协调:找出需要变动的节点)和 Commit Phase (提交更新)。
React 会霸占着浏览器资源,导致用户触发的时间得不到响应以及掉帧,因此 Fiber 将协调阶段按照优先级分段执行,任何低优先级的更新都可能被打断重来。
计划删除/即将过时的生命周期就发生在 render 前的协调阶段,因此随时可能会被打断重新执行,这些钩子函数就会变得不可预测。
a:初始化 state :转移至 constructor 的 this.state 内。
b:不建议在该生命周期内有副作用操作,如若有也可以转移至 componentDidMount 。
a:副作用操作(比如数据请求/动画):转移至 componentDidUpdate 。
b:考虑受控组件和完全非受控组件。
c:实在不行也可以使用 getDerivedStateFromProps,但务必做好条件判断。
componentWillReceiveProps
// before
componentWillReceiveProps(nextProps) {
if (nextProps.translateX !== this.props.translateX) {
this.setState({
translateX: nextProps.translateX,
});
}
}
// after
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.translateX !== prevState.translateX) {
return {
translateX: nextProps.translateX,
};
}
return null;
}
getDerivedStateFromProps 中禁止了组件去访问 this.props ,强制开发者去比较 nextProps 与 prevState 中的值,以确保当开发者用到 getDerivedStateFromProps 这个生命周期函数时,就是在根据当前的 props 来更新组件的 state ,而不是去做其他一些让组件自身状态变得更加不可预测的事情。
React 团队试图通过框架级别的 API 来约束或者说帮助开发者写出可维护性更佳的 JavaScript 代码。
// 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();
}
}
通常可以替换成 componentDidUpdate() getSnapshotBeforeUpdate()
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;
};