React生命周期

在 React 中,对于每一次由状态改变导致页面视图的改变,都会经历两个阶段:render 阶段、commit 阶段。

只有 class 组件才有生命周期,因为 class 组件会创建对应的实例,而函数组件不会。组件实例从被创建到被销毁的过程称为组件的生命周期。

由 class 组件创建的实例具有生命周期,它的 render 函数在 render 阶段执行,并在此阶段进行 DOM 节点的 diff(diff 算法就是在此阶段进行的),找出需要改变的 DOM 操作。然后在 commit 阶段将对应的 DOM 操作提交至视图中。

而 class 组件实例的所有生命周期函数,都会在 render 阶段和 commit 阶段执行。

image
注:红色为 React 17 已经废弃的生命周期钩子,绿色为新增的生命周期钩子

在首次渲染页面时,会调用 Mount 相关生命周期钩子;在之后的页面渲染中,会调用 Update 相关生命周期钩子。所以与 Mount 相关的生命周期钩子只会被调用一次。

render阶段

constructor

该方法只会执行一次,调用该方法会返回一个组件实例。
在初始化阶段执行,可直接对 this.state 赋值。其他生命周期函数中只能通过 this.setState 修改 state,不能直接为 this.state 赋值。

使用场景:
一般在 constructor 中做一些组件的初始化工作,例如:初始化组件的 state。

componentWillReceiveProps

在已挂载组件接收到新的 props 之前调用。你可以在这个函数中比较新旧 props,并根据新旧 props 更改 state。但是它会破坏 props 数据的单一数据源。

在首次渲染组件时,不会调用此生命周期钩子;使用 this.setState 触发组件更新时,也不会调用此生命周期钩子。

不过要注意:如果是父组件渲染导致了组件的重新渲染,即使传给该组件的 props 没变,该组件中的这个生命周期函数也会被调用。
我们一般不使用此生命周期函数,因为它通常会破坏数据源的单一性。

getDerivedStateFromProps

它是一个静态方法,接收 propspropsprops 和 statestatestate 两个参数。它会在调用 render 方法之前被调用,不管是在初始挂载时还是在后续组件更新时都会被调用。
它的调用时机和 componentWillMount、componentWillUpdate、componentWillReceiveProps 一样都是在 render 方法被调用之前,它可以作为 componentWillMount、componentWillUpdate 和 componentWillReceiveProps 的替代方案。
当然,它的作用不止如此,它可以返回一个对象,用来更新 state,就像它的名字一样,从 props 中获取衍生的 state。如果不需要更新 state 则可以返回 null。
需要注意的是:这个生命周期函数是类的静态方法,并不是原型中的方法,所以在其内部使用 this 访问到的不是组件实例。
此生命周期钩子不常用,如果可以的话,我们也尽可能不会使用它。
关于为什么要废弃 componentWillMount、componentWillUpdate、componentWillReceiveProps 三个生命周期钩子而新增 getDerivedStateFromProps 生命周期钩子,后面会说明原因。

shouldComponentUpdate

熟悉 React 组件生命周期的话都知道:调用 setState 方法总是会触发 render 方法从而进行 vdom re-render 相关逻辑,哪怕实际上你没有更改到 Component.state

this.state = {count: 0}
this.setState({count: 0});// 组件 state 并未被改变,但仍会触发 render 方法
为了避免这种性能上的浪费, React 提供了一个 shouldComponentUpdate 来控制触发 vdom re-render 逻辑的条件。于是 PureRenderMixin 作为一种优化技巧被使用。它仅仅是浅比较对象,深层次的数据结构根本不管用
在组件准备更新之前调用,但是首次渲染或者使用 forceUpdate 函数时不会被调用。跟它的名字一样,它用来判断一个组件是否应该更新。

默认情况下,当组件的 props 或者 state 变化时,都会导致组件更新。它在 render 方法之前执行,如果它的返回值为 false,则不会更新组件,也不会执行后面的 render 方法。

它接收两个参数,nextProps 和 nextState,即下一次更新的 props 和下一次更新的 state。我们可以将 this.props 和 nextProps 比较,以及将 this.state 与 nextState 比较,并返回 false,让组件跳过更新。不过注意:它并不会阻止子组件因为 state 改变而导致的更新。
使用场景:
这个生命周期方法通常用来做性能优化。也可以继承pureComponent来性能优化
image

componentWillMount(UNSAFE)

在组件挂载至 DOM 之前调用,并且只会调用一次。它在 render 方法之前调用,因此在 componentWillMount 中调用 this.setState 不会触发额外的渲染。
这个生命周期钩子使用频率较小,因为我们一般在 constructor 中初始化 state,在 componentDidMount 中引入副作用或者订阅内容。

componentWillUpdate(UNSAFE)

在组件即将更新之前执行,如果 shouldComponentUpdate 函数返回 false,则不会调用 componentWillUpdate 方法。
这个生命周期钩子和 componentWillMount 类似,执行的时机是相同的,只不过 componentWillMount 在组件首次渲染时执行,而 componentWillUpdate 在组件后续更新时执行。这两个生命周期函数都不经常使用。

render

render 方法是类组件中唯一必须实现的方法,它的返回值将作为页面渲染的视图。render 函数应该为纯函数,也就是对于相同的 state 和 props,它总是返回相同的渲染结果。
render 函数被调用时,会返回以下四种类型之一:

React 元素:通常为 JSX 语法。例如:

等等。
数组或者 fragments:render 方法可以通过数组返回多个元素。
Portals:渲染子节点至不同的子树中。
字符串或者数值:会作为文本节点被渲染。
boolean 类型或者 null:什么都不渲染。

需要注意的是:如果 shouldComponentUpdate 生命周期钩子返回 false,则 render 方法(render 阶段后续生命周期钩子)不会执行。

commit阶段

componentDidMount

该生命周期方法会在组件挂载之后执行,也只会执行一次,也就是将组件对应的 DOM 插入 DOM 树中之后调用。它会在浏览器更新视图之前调用,如果在 componentDidMount 中直接调用 this.setState,它会触发额外的渲染,会再一次调用 render 函数,但是浏览器中视图的更新只会执行一次。
使用场景:
依赖于 DOM 的初始化操作应该放在这里,此外,我们一般在这个生命周期方法中发送网络请求、添加订阅等。

getSnapshotBeforeUpdate

此生命周期函数在最近一次渲染提交至 DOM 树之前执行,此时 DOM 树还未改变,我们可以在这里获取 DOM 改变前的信息,例如:更新前 DOM 的滚动位置。
它接收两个参数,分别是:prevProps、prevState,上一个状态的 props 和上一个状态的 state。它的返回值将会传递给 componentDidUpdate 生命周期钩子的第三个参数。
使用场景
需要获取更新前 DOM 的信息时。例如:需要以特殊方式处理滚动位置的聊天线程等。

componentDidUpdate

在组件更新后立即调用,首次渲染不会调用该方法。它的执行时机和 componentDidMount 一致,只是 componentDidMount 在首次渲染时调用,而 componentDidUpdate 在后续的组件更新时调用。可以在这个生命周期中直接调用 this.setState,但是必须包裹在一个条件语句中,否则会导致死循环。
componentDidUpdate 接收三个参数,分别是 prevProps、prevState、snapshot,即:前一个状态的 props,前一个状态的 state、getSnapshotBeforeUpdate 的返回值。
如果组件实现了 getSnapshotBeforeUpdate 生命周期函数,则 getSnapshotBeforeUpdate 的返回值将作为 componentDidUpdate 的第三个参数。
使用场景
在这个生命周期方法中,可以对 DOM 进行操作或者进行网络请求。

componentWillUnmount

这个生命周期函数会在组件卸载以及销毁之前调用。

使用场景
通常用来执行组件的清理操作,例如:清除 timer、取消网络请求、清除订阅等。

posted @ 2022-10-19 09:51  yunChuans  阅读(33)  评论(0编辑  收藏  举报