React 15
componentReceiveProps 并不是由 props 的变化触发的,而是由父组件的更新触发的
React 16
Mounting 阶段:组件的初始化渲染(挂载)
getDerivedStateFromProps:使用 props 来派生、更新 state
- 被定义为 static,方法内部拿不到组件实例的 this
- 返回值必须是对象或 null
render 函数每次渲染时都会被调用,如果存在 setState 会触发渲染,造成死循环
// 初始化/更新时调用
static getDerivedStateFromProps(props, state) {
console.log("getDerivedStateFromProps方法执行");
// 使得本组件的 state 具有或更新 fatherText 的值为 props.text
return {
fatherText: props.text
}
}
Updating 阶段:组件的更新
用 getDerivedStateFromProps 代替 componentWillReceiveProps
- 强制推行“只用 getDerivedStateFromProps 来完成 props 到 state 的映射”这一最佳实践
- 确保生命周期函数的行为更加可控可预测
- 使用 getSnapshotBeforeUpdate 取代 componentWillUpdate
- 返回值会作为第三个参数给到 componentDidUpdate
- 此阶段可以同时获取到更新前的真实 DOM 和更新前后的 state & props 信息 ```typescript 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) { const list = this.listRef.current; return list.scrollHeight - list.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) { const list = this.listRef.current; list.scrollTop = list.scrollHeight - snapshot; } ```
生命周期更改的原因
React 16 改造生命周期的主要动机是为了配合 Fiber 架构带来的异步渲染机制 render 阶段在执行过程中允许被打断,而 commit 阶段则总是同步执行的
在 Fiber 机制下,render 阶段是允许暂停、终止和重启的。当一个任务执行到一半被打断后,下一次渲染线程抢回主动权时,这个任务被重启的形式是“重复执行一遍整个任务”而非“接着上次执行到的那行代码往下走”。这就导致 render 阶段的生命周期都是有可能被重复执行的。
React 16 打算废弃的是哪些生命周期:
- componentWillMount;
- componentWillUpdate;
- componentWillReceiveProps。
这些生命周期的共性,就是它们都处于 render 阶段,都可能重复被执行,而且由于这些 API 常年被滥用,它们在重复执行的过程中都存在着不可小觑的风险。