首页  >  文章  >  web前端  >  React 生命周期方法

React 生命周期方法

王林
王林原创
2024-09-05 06:38:41989浏览

在 React 中,生命周期方法是在组件存在的不同阶段调用的特殊方法。它们允许您控制组件在安装、更新或卸载等各个阶段发生的情况。随着 React 16.8 中 React Hooks 的引入,函数式组件也可以管理自己的副作用,但生命周期方法在类组件中仍然很重要。以下是最常用的生命周期方法的详细介绍:

安装

React 中的挂载阶段是指组件被创建并插入到 DOM 中的过程。此阶段涉及按特定顺序调用的一系列生命周期方法,允许开发人员在渲染组件之前对其进行初始化和配置。以下是安装阶段中每个方法的详细分解(按执行顺序排列):

1. 构造函数(props)

目的:

  • 构造函数是创建组件实例时调用的第一个方法。它用于初始化组件的状态并绑定事件处理程序。

  • 在构造函数中,可以通过直接给this.state赋值一个对象来设置初始状态。您通常还使用 super(props) 将 props 传递给基 Component 类,以确保组件正确初始化。

示例:

React Lifecycle Methods

备注:

  • 构造函数在组件的生命周期中只调用一次。

  • 您应该避免构造函数中的副作用(例如网络请求或订阅)并为 componentDidMount 保留这些任务。

2. 静态 getDerivedStateFromProps(props, 状态)

目的:

  • 这是一个静态方法,在渲染之前调用,无论是在初始安装期间还是在更新期间。它允许组件根据 props 的变化更新其状态。

  • 它返回一个对象来更新状态,如果不需要状态更新则返回 null。

示例:

React Lifecycle Methods

备注:

  • 很少需要这个方法,因为 React 的数据流通常是通过直接传递 props 来处理的。

  • 它用于需要从 props 导出状态的特殊情况。

3. 渲染()

目的:

  • render 方法是类组件中唯一必需的生命周期方法。它通过返回 React 元素来确定组件的 UI 应该是什么样子。

  • 这个方法是纯粹的,这意味着它不应该修改组件状态或与 DOM 交互。

示例:

React Lifecycle Methods

备注:

  • render 方法可以返回各种值,包括 JSX 元素、数组、片段、门户、字符串、数字或 null。

  • 由于渲染是纯粹的,请避免此方法中的副作用或状态突变。

4. 组件DidMount()

目的:

  • 此方法在组件安装(即插入到 DOM 中)后立即调用。它是运行副作用的完美场所,例如从 API 获取数据、设置订阅或初始化第三方库。

  • componentDidMount 是安装阶段调用的最后一个方法,使其成为任何 DOM 操作的理想选择。

示例:

React Lifecycle Methods

备注:

  • 由于在初始渲染后调用了 componentDidMount,因此更新其中的状态将触发重新渲染。这在获取数据或与 DOM 交互时很常见。

  • 如果你在这里设置了订阅或者事件监听器,记得在 componentWillUnmount 中清理它们,以避免内存泄漏。

更新中

React 中的更新阶段是指组件由于状态或 props 的变化而重新渲染的过程。在此阶段中,会按特定顺序调用多个生命周期方法,使您能够控制组件对这些更改的反应方式。下面按照执行顺序详细介绍了更新阶段涉及的每个方法:

1.静态 getDerivedStateFromProps(props, 状态)

目的:

  • 当收到新的 props 或 state 时,会在渲染组件之前调用此静态方法。它允许组件根据 props 的变化更新其内部状态。

  • 它返回一个更新状态的对象,如果不需要更新则返回 null。

示例:

React Lifecycle Methods

备注:

  • 该方法在需要与 props 同步 state 的场景中很有用。

  • 每次更新都会调用它,因此请避免此处进行繁重的计算。

2.shouldComponentUpdate(nextProps, nextState)

目的:

  • 当收到新的 props 或 state 时,在渲染之前调用此方法。它允许您控制组件是否应该更新。返回true(默认)意味着组件将更新;返回 false 表示不会。

  • 主要用于通过防止不必要的重新渲染来优化性能。

示例:

React Lifecycle Methods

备注:

  • 在初始渲染期间或使用forceUpdate() 时不会调用此方法。

  • 此处避免复杂的逻辑,因为如果处理不当,可能会导致性能问题或错误。

3. 渲染()

目的:

  • 调用 render 方法,根据组件的当前状态和 props 生成下一个版本的虚拟 DOM。

  • 它是纯粹的,这意味着它不应该修改组件状态或与 DOM 交互。

示例:

React Lifecycle Methods

备注:

  • 由于渲染是纯粹的,任何状态或道具的更改都应该反映在返回的 JSX 中。

  • 避免渲染中的副作用(例如直接修改 DOM 或发出网络请求)。

4. getSnapshotBeforeUpdate(prevProps, prevState)

目的:

  • 此方法在虚拟 DOM 的更改实际反映到真实 DOM 之前调用。它允许您在可能更改之前捕获一些信息(例如当前滚动位置)。

  • 从此方法返回的值作为第三个参数传递给 componentDidUpdate。

示例:

React Lifecycle Methods

备注:

  • 此方法对于在 DOM 更改之前捕获有关 DOM 的信息特别有用,例如在更新期间保持滚动位置。

  • 经常与componentDidUpdate一起使用。

5. componentDidUpdate(prevProps, prevState, snapshot)

目的:

  • 更新发生后立即调用此方法。这是执行任何 DOM 操作、网络请求或基于更新的其他副作用的好地方。

  • 它接收之前的 props 和 state,以及 getSnapshotBeforeUpdate 返回的值(如果有)。

示例:

React Lifecycle Methods

备注:

  • 此方法对于执行 DOM 更新后需要发生的操作很有用。

  • 避免在 componentDidUpdate 中设置状态,除非将其包装在条件中以防止无限循环更新。

卸载

React 中的卸载阶段发生在从 DOM 中删除组件时。此阶段有一个生命周期方法,允许您在组件被销毁之前执行任何必要的清理任务。正确处理此阶段对于防止内存泄漏、悬空事件侦听器或组件删除后可能持续存在的其他副作用至关重要。

1. 组件WillUnmount()

目的:
componentWillUnmount 在组件被卸载和销毁之前立即调用。该方法用于清理活动,例如:

  • 取消网络请求。

  • 清除计时器或间隔。

  • 删除事件侦听器。

  • 清理订阅(例如,来自 Redux、WebSockets 等)。

  • 使 componentDidMount 或其他生命周期方法中创建的任何副作用失效或清除。

示例:

React Lifecycle Methods

在此示例中:

  • 组件安装(componentDidMount)时启动计时器。

  • 在 componentWillUnmount 中清除计时器,以确保组件从 DOM 中移除后不会继续运行。这对于防止潜在的内存泄漏或意外行为至关重要。

主要考虑因素:

  • 防止内存泄漏:如果在 componentDidMount 中设置了事件监听器或间隔,则必须在 componentWillUnmount 中将其删除以防止内存泄漏。如果不这样做,可能会导致您的应用程序随着时间的推移消耗更多内存或出现意外行为。

  • 清理订阅:如果您的组件订阅了外部数据源(如 Redux 存储、Firebase、WebSocket 连接等),您应该在 componentWillUnmount 中取消订阅。这可确保您的组件在被删除后不再对来自这些源的更新做出反应。

  • 没有 setState: 由于组件即将被销毁,因此您不应该在 componentWillUnmount 中调用 setState。这样做不会有任何效果,因为组件不会重新渲染。

  • 异步清理:如果您的清理涉及异步操作(例如取消网络请求),请确保正确处理这些操作以避免竞争条件或尝试与不再使用的组件进行交互存在。

常见用例:

  • 计时器和间隔: 清除 setTimeout 或 setInterval 实例,以避免它们在组件卸载后运行。

  • 事件监听器: 删除附加到窗口、文档或任何 DOM 元素的事件监听器,以防止它们在组件卸载后触发。

  • 订阅: 取消订阅数据流或外部服务(例如 WebSockets、Firebase、Redux 存储)。

  • 网络请求:如果在请求完成之前卸载组件,则取消正在进行的网络请求。这可以使用 Axios 等提供取消令牌的库来完成。

最佳实践:

  • 如果在 componentDidMount 或任何其他生命周期方法中设置了副作用,请始终清除 componentWillUnmount 中的副作用。

  • 注意异步操作,以确保它们不会无意中与已卸载的组件交互。

  • 避免任何假设组件在调用 componentWillUnmount 后将继续存在的逻辑。

错误处理

React 中的错误处理阶段旨在捕获和处理渲染期间、生命周期方法以及组件下整个树的构造函数中发生的错误。这是通过使用类组件中称为错误边界的特殊生命周期方法来完成的。

误差边界概述

  • 错误边界是 React 组件,它可以在其子组件树中的任何位置捕获 JavaScript 错误,记录这些错误,并显示后备 UI,而不是使整个应用程序崩溃。这可以防止错误传播到应用程序的根目录,从而使应用程序更具弹性。

1. 静态 getDerivedStateFromError(错误)

目的:

  • 当渲染阶段、生命周期方法或任何子组件的构造函数中抛出错误时,将调用此静态方法。

  • 它允许您更新状态,以便下一个渲染将显示后备 UI。

用法:

  • 该方法接收作为参数抛出的错误,并返回一个更新组件状态的对象。

  • 通过在此方法中设置状态,您可以呈现一个后备 UI,通知用户出现了问题。

示例:

React Lifecycle Methods

备注:

  • 此方法允许您控制发生错误时渲染的内容。例如,您可以选择呈现通用错误消息或自定义错误组件。

  • 它通常用于设置可以触发后备 UI 渲染的错误状态。

2. componentDidCatch(错误,信息)

目的:

  • 在后代组件抛出错误后调用此方法。它用于记录错误信息或执行副作用,例如向错误跟踪服务报告错误。

  • 与 getDerivedStateFromError 不同,此方法可用于捕获有关错误以及发生错误的组件堆栈跟踪的其他详细信息。

用法:
该方法接收两个参数:

  • 错误:抛出的错误。

  • info:具有 componentStack 属性的对象,其中包含一个字符串,其中包含有关哪个组件引发错误的信息。

示例:

React Lifecycle Methods

备注:

  • componentDidCatch 对于记录错误或将错误发送到监控服务(例如 Sentry、LogRocket)特别有用。

  • getDerivedStateFromError 有助于渲染后备 UI,而 componentDidCatch 则专注于捕获和记录错误详细信息。

如何使用误差边界

  • 包装组件: 错误边界可用于包装任何组件或组件集。这可以全局完成(例如,围绕整个应用程序)或更选择性地完成(例如,围绕更容易出错的组件)。

示例:

React Lifecycle Methods

在此示例中,ErrorBoundary 包装了 MyComponent。如果 MyComponent 或其任何子组件抛出错误,ErrorBoundary 将捕获该错误并显示后备 UI。

主要考虑因素:

错误边界捕获以下场景中的错误:

  • 渲染期间。

  • 生命周期方法中(包括类组件中的方法)。

  • 在子组件的构造函数中。

错误边界不会捕获以下场景中的错误:

  • 事件处理程序(可以使用事件处理程序本身内的 try/catch 块捕获错误)。

  • 异步代码(例如 setTimeout、requestAnimationFrame)。

  • 服务器端渲染。

  • 错误边界本身抛出的错误(尽管您可以嵌套错误边界来捕获此类错误)。

最佳实践:

  • 使用错误边界来防止整个应用程序因小的、孤立的错误而崩溃。

  • 在应用中可能容易出错的部分周围放置错误边界,例如第三方组件或处理复杂逻辑的组件。

  • 确保错误边界提供用户友好的后备 UI,通知用户出现了问题。

理解这些生命周期方法将帮助你更好地管理 React 组件中的状态、props 和副作用。

功能组件中的生命周期方法

在函数式组件中,React 的 useEffect hook 是处理副作用和生命周期方法的主要方式。 useEffect 钩子可以复制类似于类组件生命周期方法(如 componentDidMount、componentDidUpdate 和 componentWillUnmount)的行为。下面详细介绍了 useEffect 的工作原理以及它与这些生命周期方法的关系。

基本语法

React Lifecycle Methods

  • 第一个参数(效果): 放置副作用逻辑的函数。该函数可以返回一个清理函数,用于在组件卸载时或效果重新运行之前清理资源。

  • 第二个参数(依赖项): 一组依赖项,用于确定何时应重新运行效果。如果此数组中的任何值发生变化,则会再次触发效果。

useEffect 作为 componentDidMount

要复制 componentDidMount 的行为(在组件安装后运行一次),您可以使用带有空依赖数组 [] 的 useEffect。

示例:

React Lifecycle Methods

  • 行为:该效果仅在初始渲染后运行一次,类似于类组件中的 componentDidMount。

useEffect 作为 componentDidUpdate

为了模仿 componentDidUpdate,您可以使用带有依赖项的 useEffect。只要任何依赖项发生变化,效果就会运行。

示例:

React Lifecycle Methods

  • 行为:效果在每次渲染后运行,其中依赖项(count 或 someProp)发生变化,就像 componentDidUpdate 一样。

useEffect 作为 componentWillUnmount

要复制 componentWillUnmount,您需要从 useEffect 返回一个清理函数。此清理函数将在组件卸载时或效果重新运行之前执行。

示例:

React Lifecycle Methods

  • 行为:清理函数在组件即将卸载时运行,类似于 componentWillUnmount。

在一个 useEffect 中处理所有三种生命周期方法

在许多情况下,单个 useEffect 可以处理组件的安装、更新和卸载阶段。这是一个演示这一点的示例:

示例:

React Lifecycle Methods

  • 安装:效果在初始渲染时运行一次。

  • 更新:每当 someProp 更改时效果就会运行。

  • 卸载:当组件卸载时或由于依赖项更改而重新运行效果之前,清理函数将运行。

控制useEffect的执行频率

useEffect 的行为由依赖数组控制:

  • 无依赖数组:效果在每次渲染后运行。

  • 空依赖数组 []: 该效果仅在初始渲染后运行一次(模仿 componentDidMount)。

  • 特定依赖项:只要任何指定的依赖项发生更改,效果就会运行。

  • 示例: 没有依赖数组

React Lifecycle Methods

  • 行为:效果在每次渲染(初始和更新)后运行。

常见陷阱和最佳实践

  • 避免丢失依赖项: 始终将 useEffect 中使用的所有状态和 props 包含在依赖项数组中,以避免陈旧的闭包和错误。

  • 多个 useEffect 调用: 在单个组件中使用多个 useEffect 钩子是很常见的,建议使用多个 useEffect 钩子,每个钩子负责特定的副作用。这使代码更加模块化并且更易于管理。

  • 清理: 始终考虑清理涉及订阅、计时器或组件卸载或重新触发效果时应释放的任何其他资源的效果。

有效地理解和使用 useEffect 可以让您在功能组件中以干净、可预测的方式管理副作用,提供与类组件具有生命周期方法相同的功能。

以上是React 生命周期方法的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn