💡 如果还不了解 HTML 、 CSS和JS,可以参考本号下的 HTML21 天入门教程、 CSS 21 天入门教程和JS21天入门教程。
组件的生命周期指组件从创建到卸载的全过程。
在这个过程中的不同阶段,内置了一些函数用以执行需要的逻辑处理。
React 的生命周期经过版本的迭代,有了一些变化。
这里介绍的生命周期基于版本 18。
生命周期阶段
组件的生命周期有以下三个阶段:
- 挂载阶段(Mounting):组件实例被创建和插入 DOM 树的过程。
- 更新阶段(Updating):组件被重新渲染的过程。
- 卸载阶段(Unmounting):组件从 DOM 树中被删除的过程。
它的简洁示意图如下:
Render
阶段:纯净且不包含副作用,可能会被 React 暂停、中止或重新启动。Commit
挂载阶段(Mounting)
挂载阶段的触发时间,是在组件实例被创建和插入 DOM 中时。
在这个过程中,主要以实现组件状态的初始化为主。
构造函数 constructor
构造函数在组件初始化的时候触发一次。它主要用于 设置初始化状态 和 绑定成员函数上下文引用。
如果不初始化 state
或不进行方法绑定,则不需要为 React 组件实现构造函数。
在 constructor()
函数中不要调用 setState()
方法。
如果需要使用内部 state
,直接在构造函数中为 this.state
赋值初始 state
。
constructor(props) { super(props); // 不要在这里调用 this.setState() this.state = { counter: 0 }; this.handleClick = this.handleClick.bind(this);}
切记,只能在构造函数中直接为 this.state
赋值。
static getDerivedStateFromProps
getDerivedStateFromProps
会在调用 render
方法之前调用,并且在初始挂载及后续更新时都会被调用。
它应返回一个对象来更新 state
,如果返回 null
则不更新任何内容。
该函数是静态函数,函数体内无法访问指向当前组件实例的指针 this
。
渲染函数 render
唯一的一定不能省略的函数,必须有返回值。
它仅用于渲染的纯函数,返回值完全取决于 state
和 props
的变化。
如果返回 null
或 false
表示不渲染任何 DOM 元素。
此渲染函数并不做实际的渲染动作(渲染到 DOM 树),它返回的只是一个 JSX 的描述对象(及组件实例)。
何时进行真正的渲染是有 React 库决定的。
而 React 则是要把所有组件返回的结果综合起来,才能知道如何产生真实的 DOM 树。
也就是说,只有调用所有组件的渲染函数之后,才有可能完成 DOM 装载,这时候才会依次调用 componentDidMount
函数作为装载的收尾。
保持 render()
纯粹,可以使服务器端渲染更加切实可行,也使组件更容易被理解。
💡 如果 shouldComponentUpdate() 返回 false,则不会调用 render()。
挂载成功函数 componentDidMount
componentDidMount
会在组件挂载后(插入 DOM 树中)立即调用。
依赖于 DOM 节点的初始化应该放在这里。
常用来处理比如:监听事件、获取到真实 DOM 和请求后台接口等。
componentDidMount
通常用于加载外部数据(即发送网络请求)。
之所以在 componentDidMount
中而不是在构造函数中进行数据请求的原因在于:如果数据加载完毕后,即 props
已经有值了,但是组件还没有渲染出来,会报错。
但是这里有一些把数据拉取提前到 constructor
函数的思路:在 contructor
函数中,通过 Promise
来进行数据的请求,并且绑定到当前实例对象上,然后在 componentDidMount
中执行 Promise
把数据更新到 props 上。
此函数中允许使用 setState
改变组件内 State
。
更新阶段(Updating)
属性(Props
)或状态(State
)的改变会触发一次更新阶段操作,但是组件未必会重新渲染,这取决于 shouldComponentUpdate
。
shouldComponentUpdate
shouldComponentUpdate
指定组件是否更新钩子。
每当组件因为 state
和 props
变化而更新时,在重新渲染前 shouldComponentUpdate
函数都会触发。
目的是让 React 知道当前 state
或 props
的改变是否影响组件的渲染。
由于 React 父组件的更新,必然会导致子组件的更新,因此可以在子组件中通过手动对比 props
与 nextProps
,state
与 nextState
来确定是否需要重新渲染子组件。
如果需要则返回 true
,不需要则返回 false
。该函数默认返回 true
。
💡 请勿在 shouldComponentUpdate
函数中使用 setState
方法,会导致循环调用。
getSnapshotBeforeUpdate
getSnapshotBeforeUpdate
用于保存状态快照。
它会在组件即将挂载时触发,它的触发在 render
渲染函数之后。render
函数并没有完成挂载操作,而是进行构建抽象 UI(也就是 Virtual DOM)的工作。
这使得组件能在发生更改之前从 DOM 中捕获一些信息。
此组件返回的任何值将作为 componentDidUpdate
的第三个参数。
componentDidUpdate
componentDidUpdate
是更新完成函数。
componentDidUpdate
方法在组件更新完后被调用。
因为组件已经重新渲染,所以这里可以对组件中的 DOM 进行操作。
在比较了 this.props 和 nextProps 的前提下可以发送网络请求。
在 componentDidUpdate
中使用 setState 时,必须加 if 条件判断 prevProps
、prevState
和 this.state
之间的数据变化。
这使得尽管在 componentDidUpdate
中调用了 setState
进行再更新,但是直至条件不成立,就不会造成程序死循环。
卸载阶段(Unmounting)
卸载阶段主要是从 DOM 树中删除组件,它只有一个 componentWillUnmount
函数。
componentWillUnmount
componentWillUnmount
是预卸载函数。
它在组件卸载和销毁之前触发。
可以利用 componentWillUnmount
方法去执行任何清理类的任务。
比如,注销事件监听器、取消网络请求、取消定时器、解绑 DOM 事件等。
要注意的是,如果在该方法中调用 setState
,不会触发 render
。
函数组件的生命周期
函数组件是更彻底的状态驱动抽象,甚至没有类组件生命周期的概念,只有一个状态,React 则负责同步到 DOM。
那么在函数组件中是如何做的呢?
答案是使用钩子。
💡 钩子(hook)是计算机程序设计术语。指通过拦截软件模块间的函数调用、消息传递、事件传递来修改或扩展操作系统、应用程序或其他软件组件的行为的各种技术。处理被拦截的函数调用、事件、消息的代码,被称为钩子(hook)。
至于如何使用钩子,明天继续。
总结
- 🍑 组件的生命周期有三个阶段:挂载阶段、更新阶段和卸载阶段。
- 🍑 渲染函数 render 是唯一的一定不能省略的函数,且必须有返回值。
- 🍑 函数组件是更彻底的状态驱动抽象,通过使用钩子实现生命周期的函数处理。
该文章在 2024/12/4 15:30:50 编辑过