react16版本以后,react的生命周期发生了改变,弃用了之前的
componentWillMount()、componentWillReceiveProps()、componentWillUpdate();新增了static getDerivedStateFromProps()、getSnapshotBeforeUpdate()。之前项目用的一直是旧生命周期,对新生命周期没有过多了解,现在有时间,想去多了解一下。
下边带着几个问题,去学习新的生命周期。
问题一:为什么要弃用原有生命周期?
弃用生命周期:
componentWillMount
componentWillReceiveProps
componentWillUpdate
**弃用的生命周期方法,经常被误解和滥用,是不安全的。**如:
1:在 componentWillMount 中获取数据可以避免第一次渲染为空的状态。实际上,这是不对的,因为 React 总是在 componentWillMount 之后立即执行 render。如果在 componentWillMount 触发时数据不可用,那么第一次 render 仍然会显示加载的状态,而不管你在哪里初始化获取数据。这就是为什么在绝大多数情况下,将获取数据移到 componentDidMount 没有明显效果的原因。
2:在组件挂载时订阅了外部事件,这可能导致服务器渲染(永远不会调用 componentWillUnmount)和异步渲染(在渲染完成之前可能被中断,导致不调用 componentWillUnmount)的内存泄漏。人们通常认为 componentWillMount 和 componentWillUnmount 是成对出现的,但这并不能保证。只有调用了 componentDidMount 之后,React 才能保证稍后调用 componentWillUnmount 进行清理。
3、在异步模式下使用 componentWillUpdate 都是不安全的,因为外部回调可能会在一次更新中被多次调用。相反,应该使用 componentDidUpdate 生命周期,因为它保证每次更新只调用一次。
4、componentWillReceiveProps 可能在一次更新中被多次调用。因此,避免在此方法中产生副作用非常重要。相反,应该使用 componentDidUpdate,因为它保证每次更新只调用一次。
新的生命周期:static getDerivedStateFromProps()是个纯函数,不能执行副作用(如异步调用数据等)。很大程度上避免了误操作。将副作用操作放到componentDidUpdate,保证每次更新只调用一次,而不是不管是不是更新完成了,进行了多次调用,出现卡死等问题。
详细内容可以去 react官网 查看,很详细。
问题二:新生命周期作用?
static getDerivedStateFromProps(props, state)
getDerivedStateFromProps 会在调用 render 方法之前调用(每次渲染前都会触发),并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
如果你需要执行副作用(例如,数据提取或动画)以响应 props 中的更改,请改用 componentDidUpdate
**getDerivedStateFromProps和componentDidUpdate组合使用,基本可以覆盖所有componentWillReceiveProps 的使用场景。 **
getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。应返回 snapshot 的值(或 null)。
例如:
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 我们是否在 list 中添加新的 items ?
// 捕获滚动位置以便我们稍后调整滚动位置。
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 如果我们 snapshot 有值,说明我们刚刚添加了新的 items,
// 调整滚动位置使得这些新 items 不会将旧的 items 推出视图。
//(这里的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
问题三 :生命周期方法调用情况
生命周期图谱地址 projects.wojtekmaj.pl/react-lifec…
挂载
当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:
constructor()static getDerivedStateFromProps()render()componentDidMount()
更新
当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:
static getDerivedStateFromProps()shouldComponentUpdate()render()getSnapshotBeforeUpdate()componentDidUpdate()
卸载
当组件从 DOM 中移除时会调用如下方法:
componentWillUnmount()
错误处理
当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:
static getDerivedStateFromError()componentDidCatch()
总结
官网真是个好东西,仔细看看能发现很多东西,比其他博客要详细且系统。
以前都是遇到问题解决问题,了解到的东西很片面,这就是造成我查了这么多次react新生命周期,但是还是没记住,还是没了解前因后果,这次算是从头学了一遍。
很多都是从官网复制的,写的不好,请见谅,可以去官网自行查阅
感谢React官网:react.docschina.org/