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 的对象, 其中包含有关组件引发错误的栈信息

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

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