react 组件的生命周期

 

年末了, 工作需求不饱和, 又因为写了一阵子的 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 的对象, 其中包含有关组件引发错误的栈信息

该方法可以执行副作用, 用于记录错误之类的情况

此外, 还有一些即将被废弃的生命周期函数, 不推荐使用, 我也就不记录了。 还是因为懒, 哈哈!!