react生命周期

262 阅读5分钟

一、生命周期图谱


附上官网链接,如果有侵权或者冒犯,请及时提出,我会马上做出调整。

projects.wojtekmaj.pl/react-lifec…


二、组件的生命周期

每个组件都包含生命周期方法,可以重写这些方法,以便在运行过程中特定的阶段执行这些方法。React生命周期从广义上分为三个阶段:挂载、更新、卸载。

挂载:

当组件实例被创建并插入DOM中时, 其生命周期调用顺序如下:

  • construtor()
  • static getDerivesStateFromProps()不常用的生命周期
  • render()
  • componentDidMount()

更新

当组件props或者state发生变化时会自动触发更新。组件更新的生命周期调用顺序如下:

  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

卸载

  • componentWillUnMount

错误处理

  • static getDerivedStateFromError()
  • compinentDidCatch()

其他APIS

  • setState()
  • forceUpdate()


三、挂载过程

  1. constructor():数据的初始化

如果组件不初始化state或不进行方法的绑定, 则不需要为React组件实现构造函数。

在React组件挂在之前,会调用他的构造函数。在为React.Component子类实现构造函数时,应在其他语句之前调用super(props)。否则, this.props在构造函数中可能出现未定义的bug。

  • 调用constructor时,super(props)应该在最前边

下图的图中的例子,是错误的使用方式。因为此时的this实例还没有注册。所以会报Must call super constructor in derived class before accessing 'this' or returning from derived constructor的错误



下图的图中的例子,才是正确的使用方式。如果重写了constructor构造函数的话,一定要显示的继承父类。



通常,在React中, 构造函数仅用于以下两种情况:

  • 通过this.state赋值对象来初始化内部state
  • 为事件处理函数绑定实例。

注意事项:

  • 在constructor中不要调用setState方法,如果你的组件需要使用内部state,请直接在构造函数中为this.state赋值初始化state。因为此时组件还尚未挂载。setState无法在尚未挂在的组件上调用。
  • 避免将props的值赋值给state,因为props的改变不会影响到state数据对象。产生不渲染的bug

2.static getDerivedStateFromProps(props, state)

 static getDerivedStateFromProps会在调用render方法之前调用,并且在初始挂载及后续更新时都会被调用。他应返回一个对象来更新state,如果返回null则不更新任何内容。

此方法无权访问组件实例。也就是不可以使用this。

大概理解是因为:

  • static属于类,而this属于类实例化后的对象。
  • static始终在内存上, 而this实例是只有当类创建实例后, 才会存在。
  • static是该类的所有的实例的共享区域,所以在static中,是无法找到对应的实例对象的。

注意:在静态方法中,由于没有this。所以不能在调用setState,那我们可以使用return语句

返回对应的state数据。例如下图


3.render()

render方法是class组件中唯一必须实现的方法。

当render被调用时, 它会检查this.props和this.state的变化返回以下类型:

  • React元素。
  • 数组或Fragments,使render可以返回多个元素
  • Portals可以渲染子节点到不同的DOM子树中
  • 字符串或者数值类型。
  • 布尔或者null

render()函数应为纯函数,这意味着在不修改组件的state的情况下,每次调用时,都返回相同的结果,并且不要直接操作dom元素。(document.getElementsById("")等方式)。如果需要操作dom,可以在componentDidMount或者componentdidUpdate等生命周期中使用。


注意:如果shouldComponentUpdate()返回false,则不会调用render()方法。

4.componentDidMount

componentDidMount()会在组件挂载后(初次渲染,已经渲染到页面后)立即调用。

此生名周期适合dom节点的初始化,比如请求数据等。也适合添加订阅。如果添加了订阅,请在卸载生命周期componentUnMount()里取消订阅。

5.shouldComponentUpdate()

默认返回boolean类型值为true,只要props或者state改变,都会在渲染之前触发该方法。

首次渲染或者forceUpdate()不会调用该方法

如果重写该方法并且返回false,或者不显示的返回true,该组件的render、componentWillUpdate、componentDidUpdate则不会被触发调用。因为返回false就是不去渲染。


6.getSnapshotBeforeUpdate(preProps,preState)

在最近一次渲染输出之前调用。此生命周期的任何返回值都作为参数传递给componentDidUpdate()

7.componentDidUpdate(PreProps, preState, snapshot)

会在更新后立即调用,首次渲染不执行此方法。

当组件更新后,可以在此处对dom进行操作。

可以在此调用setState,但要判断好,否则死循环了。

如果组件实现了 getSnapshotBeforeUpdate生命周期(不常用),则它的返回值将作为 componentDidUpdate 的第三个参数 “snapshot” 参数传递。否则此参数将为 undefined。

8.componentWillUnMount()

会在组件卸载及销毁之前调用。此方法中可以取消订阅。在此方法中不要调用setState了。因为该组件不会再重新渲染了。

9.static getDerivedStateFromError(error)

此生命周期会在后代组件抛出错误后被调用。它将抛出的错误作为参数。

捕获到错误,可以渲染任何自定义的降级ui。

10.componentDidCatch(error, info)

此生命周期会在后代组件抛出错误后被调用。该生命周期会在‘提交阶段’被调用(更新阶段的渲染后的生命周期)


注意过时的生命周期方法,在新的代码中避免使用。

  • UNSAFE_componentWillMount()
  • UNSAFE_componentWillUpdate()
  • UNSAFE_componentWillreceiveProps()