React 16.4版本生命周期变化
16版本之前的componentWillMount、componentWillReceiveProps、componentWillUpdate将被移除;
新增 getDerivedStateFromProps、getSnapshotBeforeUpdate ;
react框架将采用异步渲染机制,上述三个周期函数将会变的不安全,产生bug;
另新增 componentDidCatch 周期函数,处理render函数渲染错误的捕捉;
componentWillMount周期函数
- 若将异步请求数据的业务放在这个函数内,也会导致首屏白屏,怎么滴也赶不上render函数渲染
- 若是服务端渲染,此函数将会被执行两次
- 服务端渲染也不能保证componentWillUnmount周期函数执行,若在componentWillMount订阅事件,则会造成内存泄漏
- 尽量将数据请求放在componentDidMount函数内执行,此时dom已挂载完毕,不会造成影响,比较安全;
componentWillReceiveProps 和 getDerivedStateFromProps 的比较
应用场景: 当组件内的state和props紧密联系时
- componentWillReceiveProps(nextProps) 更新state 执行回调函数
- getDerivedStateFromProps(nextProps, prevState) 只专注于props和state的比较,来更新state
- 比较新旧的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// 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();
}
}
在新版本中,官方将更新 state 与触发回调重新分配到了 getDerivedStateFromProps 与 componentDidUpdate 中,使得组件整体的更新逻辑更为清晰。而且在 getDerivedStateFromProps 中还禁止了组件去访问 this.props,强制让开发者去比较 nextProps 与 prevState 中的值,以确保当开发者用到 getDerivedStateFromProps 这个生命周期函数时,就是在根据当前的 props 来更新组件的 state,而不是去做其他一些让组件自身状态变得更加不可预测的事情。
componentWillUpdate 和 getSnapshotBeforeUpdate
- componentWillUpdate 都有可能在一次更新中被调用多次,显然是不可取的,将回调函数放在componentDidUpdate
- componentWillUpdate
- getSnapshotBeforeUpdate(prevProps, prevState) 返回值作为第三个参数传入componentDidUpdate
官方例子1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36class 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;
};
}