年末了, 工作需求不饱和, 又因为写了一阵子的 weex + rax, rax 的语法与 react 基本一致, 生命周期函数都是一样的, 遂趁这个时间总结一下。 其实早早就想写了, 但是一直很忙(lan), 然后就搁置到现在了, O(∩_∩)O哈哈~
声明: 参考 react 中文文档
仅此记录, 供自己学习, 如果你有幸搜到这篇文章, 推荐你直接读上面的链接
生命周期函数
刚刚开始工作那会儿, 没有接触过 vue、 react, 第一次听说生命周期函数, 也不明白是怎么回事,也不知道怎么用, 但是人都是有学习能力的, 看看别人怎么用的, 然后实际用用也就理解了。(废话好多啊。。。 哈哈)
生命周期函数, 顾名思义, 就是跟生命有关的, 我们可以把组件理解成一个有生命的个体, 它也会经历生老病死, 以人为例, 会经历 婴儿期 —> 幼儿期 —> 少年期 —> 青年期 —> 中年期 —-> 老年期 等等。 组件是一样的, 也会有各个时期, 而周期函数就是在特定的时期被调用的特定函数。
那么, 我们看看组件到底有哪些生命周期函数, 下图也是从 react 中文文档 上整下来的。
可以看到, 生命周期函数是有很多的, 但是经常使用的也就那么几个, 经常使用的这几个是必须要掌握的, 而那些不常用的也要有印象才行。
下面开始介绍各个生命周期
挂载阶段
当组件实例被创建并插入到 DOM 中时, 其生命周期函数调用顺序如下
- constructor()
- static getDerivedStateFromProps()
- render()
- componentDidMount()
更新阶段
当组件的 props 或 state 发生变化时会触发更新, 组件更新的生命周期函数调用顺序如下
- static getDerivedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
卸载阶段
当组件从 DOM 中移除时会调用如下方法
- componentWillUnmount()
错误处理
当渲染过程中,生命周期或子组件的构造函数中抛出错误时, 会调用如下方法
- static getDerivedStateFromError()
- componentDidCatch()
常用的生命周期函数
render()
render 方法是 class 组件中唯一必须实现的方法。 想想确实也是这么回事, 如果不实现这个函数, 你的组件要渲染个寂寞吗?
当 render 被调用时, 它会检查 this.props 和 this.state 的变化并返回以下类型之一:
- React 元素,(这也是最常用的一种方式了) 通常通过 JSX 创建。
- 数组或者 fragments, 使得 render 方法可以返回多个元素
- Protals,可以渲染子节点到不同的 DOM 子树中。例如, 弹窗组件、tooltip 等, 可以通过此类型绑定到 body 元素上
- 字符串或数值类型, 它们在 DOM 中会被渲染为文本节点
- 布尔类型或 null, 什么都不渲染。主要用于支持返回
test && <Child />
的模式, 其中 test 为布尔类型
render 函数应该是一个纯函数, 这就意味着在不修改组件 state 的情况下, 每次调用时都返回相同的结果, 并且它不会直接与浏览器交互
当 shouldComponentUpdate 返回 false, 则不会调用 render
constructor()
constructor(props) {}
构造函数, 当一个对象被实例化的时候会优先调用构造函数, 那么挪到 react 组件中来, 就是组件被过载之前, 就会调用构造函数。在为 React.Component
子类实现构造函数时, 应在其他语句之前调用 super(props)
, 否则, this.props
在构造函数中可能会出现未定义的 bug。
一般, 在 React 中, 构造函数仅用于以下两种情况
- 通过给
this.state
赋值对象来初始化内部 state - 为事件处理函数绑定实例。 (个人不推荐, 推荐事件处理函数使用匿名函数)
componentDidMount()
componentDidMount() {}
该生命周期函数会在组件挂载后立即被调用。 依赖于 DOM 节点的初始化应该放在这里。例如通过网路请求获取数据, 此处是实例化请求的好地方
componentDidUpdate()
componentDidUpdate(prevProps, prevState, snapshot)
componentDidUpdate() 方法会在更新后被立即调用。 首次渲染不会执行此方法
不要在该方法内直接调用 this.setState
, 会导致死循环, 如果有这样的需求,请将 this.setState
包裹在一个条件语句中
如果组件实现了 getSnapshotBeforeUpdate()
生命周期, 则它的返回值将作为 componentDidUpdate()
的第三个参数 snapshot 参数传递。 否则此参数将为 undefined
componentWillUnmount()
componentWillUnmount()
componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理逻辑,例如 清除定时器、取消网络请求等
不常用的生命周期方法
shouldComponentUpdate()
shouldComponentUpdate(nextProps, nextState)
根据该函数的返回值, 判断 React 组件的输出是否受当前 state 或 props 更改的影响, 默认行为是 state 每次发生变化组件都会重新渲染。 大部分情况下, 你应该遵循默认行为。
当 props 或 state 发生变化时, shouldComponentUpdate 会在渲染执行前被调用, 返回默认值 true。 首次渲染或使用 forceUpdate() 时不会调用该方法
此方法仅作为 性能优化而存在
static getDerivedStateFromProps()
static getDerivedStateFromProps(props, state)
getDerivedStateFromProps 会在调用 render 方法之前调用, 并且在初始挂载及后续更新时都会被调用。 它应返回一个对象来更新 state, 如果返回 null 则不更新任何内容
该方法适用于某些特殊场景, 即 state 的值在任何时候都取决于 props。
getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate 在最近一次渲染输出之前调用。 它使得组件能在发生更改之前从 DOM 中捕获一些信息。 此生命周期的任何返回值将作为参数传递给 componentDidUpdate()
Error boundaries
Error boundaries 是 React 组件, 它会在其子组件树中的任何位置捕获 JavaScript 错误, 并记录这些错误, 展示降级 UI 而不是崩溃的组件树。 Error boundaries 组件会捕获在渲染期间, 在生命周期方法以及其整个树的构造函数发生的错误
如果 class 组件定义了生命周期方法 static getDerivedStateFromError()
或 componentDidCatch()
中的任何一个(或两者),它就成为了 Error boundaries。通过生命周期更新 state 可让组件捕获树中未处理的 JavaScript 错误并展示降级 UI。
static getDerivedStateFromError()
static getDerivedStateFromError(error)
此生命周期会在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染可以显降级 UI
return { hasError: true };
}
render() {
if (this.state.hasError) {
// 你可以渲染任何自定义的降级 UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
componentDidCatch()
componentDidCatch(error, info)
此生命周期在后代组件抛出错误后被调用。 它接收两个参数
- error —— 抛出的错误
- info ——带有 componentStack key 的对象, 其中包含有关组件引发错误的栈信息
该方法可以执行副作用, 用于记录错误之类的情况
此外, 还有一些即将被废弃的生命周期函数, 不推荐使用, 我也就不记录了。 还是因为懒, 哈哈!!