一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
生命周期
生命周期(left cycle)就是指一个对象的生老病死。基本涵义可以通俗理解为从“摇篮到坟墓”(cradle-to-grave)的整个过程。
每个组件都包含 “生命周期方法”,你可以重写这些方法,以便于在运行过程中特定的阶段执行这些方法。 react官网
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。vue官网
react的生命周期从15到16.3(2018年3月29号)有很多的变化,而17,18就没有啥变化了。
React15 | React16 | ||
---|---|---|---|
挂载时 | constructor -> componentWillMount -> render -> componentDidMount | constructor -> getDerivedStateFromProps -> render -> componentDidMount | |
更新时 | componentWillReceiveProps(父更新) -> shouldComponentUpdate (自己更新) -> componentWillUpdate -> render -> compoentDidUpdate | getDerivedStateFromProps -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate | |
卸载时 | componentWillUnmount | componentWillUnmount | componentWillUnmount |
要点
16.3添加了两个钩子,同时给标记三个钩子为不安全的。
添加的钩子为:getDerivedStateFromProps,getSnapshotBeforeUpdate 。同时给componentWillMount, componentWillUpdate, componentWillReceiveProps 添加UNSAFE_别名。就是如果使用它们会明确第看到警告信息。 17.0 彻底移除上面的三个钩子。 参考
React16开始慢慢从生命周期中去掉了componentWillMout
和componentWillUpdate
方法,并且使用getDerivedStateFromProps
方法替代了之前的componentWillReceiveprops
。
原因是:
- 用户经常会在这个三个钩子中嵌入错误的业务代码,导致异常。为了减少这类错误的使用,直接删除它们
- 给Fiber机制的引入打下基础。移除的三个钩子都有关键字will,他们都是在render()之前完成的。在Fiber架构下,又将生命周期划分了如下三个阶段:
- (1)render阶段:纯净且没有副作用,可能会被暂停或者终止,重新启动。getDerivedStateFromProps -> shouldComponentUpdate -> render
- (2)Pre-commit阶段:可以读取DOM。getSnapshotBeforeUpdate()
- (3)commit阶段:可以使用DOM,运行副作用,安排更新。componentDidUpdate() 在Fiber架构下,render阶段是可能会被React暂停,终止或者重新启动的。如果这三个钩子还处在其中,会导致更大的维护风险。
getDerivedStateFromProps
它是一个比较特别的钩子:
- 唯一个静态的方法:要在前面加static,且内部无法拿到组件实例。
- 父组件触发导致的更新,它的执行顺序是:getDerivedStateFromProps -> shouldComponentUpdate -> render。
- 返回一个对象来更新 state,如果返回
null
则不更新任何内容。 参考
componentWillUnmount
componentWillUnmount()
会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如:
- 清除 timer
- 取消网络请求
- 清除在
componentDidMount()
中创建的事件监听
不应调用 setState()
,因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate()
在componentDidUpdate之前调用。它任何返回值将作为参数传递给 componentDidUpdate()
。
它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。
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>
);
}
}
在上述示例中,重点是从 getSnapshotBeforeUpdate
读取 scrollHeight
属性,因为 “render” 阶段生命周期(如 render
)和 “commit” 阶段生命周期(如 getSnapshotBeforeUpdate
和 componentDidUpdate
)之间可能存在延迟。