深入理解 React 组件的生命周期:从创建到销毁的全过程

news2025/4/22 20:57:56

React 作为当今最流行的前端框架之一,其组件生命周期是每个 React 开发者必须掌握的核心概念。本文将全面剖析 React 组件的生命周期,包括类组件的各个生命周期方法和函数组件如何使用 Hooks 模拟生命周期行为,帮助开发者编写更高效、更健壮的 React 应用。

一、React 组件生命周期概述

React 组件的生命周期指的是一个组件从创建、更新到销毁的整个过程。在这个过程中,React 提供了许多"生命周期方法",允许开发者在特定的阶段执行自定义代码。理解这些生命周期方法对于控制组件行为、优化性能以及管理副作用至关重要。

React 的生命周期可以分为三个主要阶段:

  1. 挂载阶段(Mounting):组件被创建并插入到 DOM 中

  2. 更新阶段(Updating):组件的 props 或 state 发生变化时的重新渲染过程

  3. 卸载阶段(Unmounting):组件从 DOM 中移除

此外,React 16 还引入了错误处理生命周期方法,用于捕获和处理组件树中的 JavaScript 错误。

二、类组件的生命周期详解

1. 挂载阶段(Mounting)

挂载阶段是组件第一次被创建并插入到 DOM 中的过程,包含以下生命周期方法:

constructor()
constructor(props) {
  super(props);
  this.state = { count: 0 };
  this.handleClick = this.handleClick.bind(this);
}
  • 最先执行的生命周期方法

  • 必须调用 super(props),否则 this.props 将会是 undefined

  • 唯一可以直接修改 this.state 的地方

  • 用于初始化 state 和绑定事件处理方法

static getDerivedStateFromProps()
static getDerivedStateFromProps(props, state) {
  if (props.value !== state.prevValue) {
    return {
      value: props.value,
      prevValue: props.value
    };
  }
  return null;
}
  • 在 render 方法之前调用,无论是初始挂载还是后续更新

  • 应返回一个对象来更新 state,或返回 null 不更新

  • 用于 state 依赖于 props 变化的罕见情况

  • 此方法无权访问组件实例(即不能使用 this)

render()
render() {
  return <div>{this.state.count}</div>;
}
  • 类组件中唯一必须实现的方法

  • 应该是一个纯函数,不修改组件状态,不与浏览器交互

  • 返回以下类型之一:

    • React 元素(JSX)

    • 数组或 fragments

    • Portals

    • 字符串或数值(渲染为文本节点)

    • 布尔值或 null(不渲染任何内容)

componentDidMount()
componentDidMount() {
  // 典型用法:
  fetchData().then(data => this.setState({ data }));
  // 或
  this.subscription = dataSource.subscribe(this.handleDataChange);
}
  • 组件挂载(插入 DOM 树)后立即调用

  • 适合执行有副作用的操作:

    • 网络请求

    • 设置订阅

    • 手动操作 DOM

  • 可以在此处直接调用 setState(),但会触发额外渲染

2. 更新阶段(Updating)

当组件的 props 或 state 发生变化时,会触发更新阶段的生命周期方法:

static getDerivedStateFromProps()
  • 同挂载阶段,在每次渲染前调用

shouldComponentUpdate()
shouldComponentUpdate(nextProps, nextState) {
  // 只有当count变化时才重新渲染
  return nextState.count !== this.state.count;
}
  • 决定组件是否应该更新

  • 返回 false 可以阻止组件重新渲染

  • 主要用于性能优化

  • 不建议深层比较或使用 JSON.stringify(),影响性能

  • 考虑使用 PureComponent 替代手动实现

render()
  • 同挂载阶段

getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate(prevProps, prevState) {
  if (prevProps.items.length < this.props.items.length) {
    const list = this.listRef.current;
    return list.scrollHeight - list.scrollTop;
  }
  return null;
}
  • 在最近一次渲染输出(提交到 DOM 节点)之前调用

  • 使得组件能在 DOM 变化前捕获一些信息(如滚动位置)

  • 返回值将作为 componentDidUpdate() 的第三个参数

componentDidUpdate()
componentDidUpdate(prevProps, prevState, snapshot) {
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
  
  if (snapshot !== null) {
    const list = this.listRef.current;
    list.scrollTop = list.scrollHeight - snapshot;
  }
}
  • 更新完成后调用(首次渲染不会执行)

  • 适合执行有副作用的操作:

    • 网络请求(需比较 props)

    • DOM 操作

  • 可以调用 setState(),但必须包裹在条件语句中,否则会导致无限循环

3. 卸载阶段(Unmounting)

componentWillUnmount()
componentWillUnmount() {
  clearInterval(this.timerID);
  this.subscription.unsubscribe();
}
  • 组件卸载及销毁前调用

  • 用于执行必要的清理操作:

    • 清除定时器

    • 取消网络请求

    • 清理订阅

  • 不应调用 setState(),因为组件永远不会重新渲染

4. 错误处理

React 16 引入了错误边界的概念,用于捕获子组件树中的 JavaScript 错误。

static getDerivedStateFromError()
static getDerivedStateFromError(error) {
  return { hasError: true };
}
  • 在后代组件抛出错误后被调用

  • 接收错误作为参数

  • 应返回一个状态对象以更新 state,用于渲染备用 UI

componentDidCatch()
componentDidCatch(error, info) {
  logErrorToService(error, info.componentStack);
}
  • 在后代组件抛出错误后被调用

  • 接收两个参数:

    • error - 抛出的错误

    • info - 包含 componentStack 键的对象

  • 用于记录错误信息

三、函数组件的"生命周期"

随着 React Hooks 的引入,函数组件现在也能实现类组件的生命周期功能。以下是常用 Hooks 与生命周期方法的对应关系:

useState - 状态管理

const [count, setCount] = useState(0);
  • 相当于类组件中的 this.state 和 this.setState

  • 可以在函数组件中添加局部 state

useEffect - 副作用管理

useEffect(() => {
  // 相当于 componentDidMount 和 componentDidUpdate
  document.title = `You clicked ${count} times`;
  
  return () => {
    // 相当于 componentWillUnmount
    // 清理函数
  };
}, [count]); // 仅在 count 更改时更新
  • 组合了 componentDidMount, componentDidUpdate 和 componentWillUnmount

  • 第一个参数是 effect 函数,第二个参数是依赖数组

  • 返回的函数是清理函数,在组件卸载时执行

useLayoutEffect

useLayoutEffect(() => {
  // 在 DOM 更新后同步执行
  const { width } = node.getBoundingClientRect();
  setWidth(width);
});
  • 与 useEffect 签名相同,但调用时机不同

  • 在 DOM 变更后同步触发

  • 适用于需要读取 DOM 布局并同步重新渲染的情况

useMemo 和 useCallback - 性能优化

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedCallback = useCallback(() => doSomething(a, b), [a, b]);
  • 相当于 shouldComponentUpdate 的优化

  • 用于避免不必要的计算和渲染

四、新旧生命周期对比与最佳实践

React 16.3 对生命周期方法进行了重大调整,废弃了一些不安全的生命周期方法:

废弃的方法:

  • componentWillMount

  • componentWillReceiveProps

  • componentWillUpdate

这些方法被标记为不安全主要是因为:

  1. 它们经常被误用和滥用

  2. 在异步渲染中可能导致问题

  3. 容易引入副作用和错误

最佳实践建议:

  1. 将数据获取移到 componentDidMount 或 useEffect 中

  2. 使用 getDerivedStateFromProps 替代 componentWillReceiveProps

  3. 使用 getSnapshotBeforeUpdate 替代 componentWillUpdate

  4. 考虑使用函数组件和 Hooks 替代类组件

  5. 谨慎使用派生 state,多数情况下可以通过提升 state 或受控组件解决

五、实际应用场景示例

场景1:数据获取

class UserProfile extends React.Component {
  state = { user: null, loading: true };
  
  async componentDidMount() {
    const user = await fetchUser(this.props.userId);
    this.setState({ user, loading: false });
  }
  
  async componentDidUpdate(prevProps) {
    if (this.props.userId !== prevProps.userId) {
      this.setState({ loading: true });
      const user = await fetchUser(this.props.userId);
      this.setState({ user, loading: false });
    }
  }
  
  componentWillUnmount() {
    // 取消可能的未完成请求
  }
  
  render() {
    // 渲染用户信息
  }
}

场景2:滚动位置恢复

class ScrollList extends React.Component {
  getSnapshotBeforeUpdate(prevProps) {
    if (prevProps.items.length < this.props.items.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }
  
  componentDidUpdate(prevProps, prevState, snapshot) {
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }
  
  render() {
    return (
      <div ref={this.listRef}>
        {/* 列表内容 */}
      </div>
    );
  }
}

场景3:错误边界

class ErrorBoundary extends React.Component {
  state = { hasError: false };
  
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  
  componentDidCatch(error, info) {
    logErrorToService(error, info.componentStack);
  }
  
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children; 
  }
}

总结

React 组件的生命周期是 React 应用的核心机制,理解这些生命周期方法对于构建高效、可靠的 React 应用至关重要。随着 React 的发展,生命周期方法也在不断演进,从类组件的各种生命周期方法到函数组件的 Hooks,React 提供了更灵活、更简洁的方式来管理组件的生命周期。

对于新项目,建议优先考虑使用函数组件和 Hooks,它们提供了更简洁的代码组织和更强大的组合能力。对于现有项目,了解类组件的生命周期仍然很重要,特别是在维护老代码时。

记住,生命周期方法是你控制组件行为的工具,正确使用它们可以:

  • 优化性能

  • 管理副作用

  • 处理错误

  • 保持代码整洁和可维护

通过掌握 React 组件的生命周期,你将能够构建更强大、更可靠的 React 应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2340335.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenCV 图形API(44)颜色空间转换-----将图像从 BGR 色彩空间转换为 RGB 色彩空间函数BGR2RGB()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从BGR色彩空间转换为RGB色彩空间。 该函数将输入图像从BGR色彩空间转换为RGB。B、G和R通道值的常规范围是0到255。 输出图像是8位无符号3通…

配置nginx服务,通过多ip区分多网站

首先关闭防火墙,setenforce 0 关过了,不截图了 多IP,首先配置多个IP地址 可以在vm增加虚拟网卡,也可以在同一网卡配置多个IP,我用第一种 记得点确定 查看新的虚拟网卡IP 没有IP,配置一个 安装nginx 写配置 server{listen 192.168.214.130:80;root /www/ip/130; # 资源根目…

[k8s实战]Containerd 1.7.2 离线安装与配置全指南(生产级优化)

[k8s实战]Containerd 1.7.2 离线安装与配置全指南&#xff08;生产级优化&#xff09; 摘要&#xff1a;本文详细讲解在无外网环境下部署 Containerd 1.7.2 容器运行时的完整流程&#xff0c;涵盖二进制包安装、私有镜像仓库配置、Systemd服务集成等关键步骤&#xff0c;并提供…

解决Windows安全中心显示空白页面

1、电脑重装系统后&#xff0c;发现原本一些软件打不开了&#xff0c;电脑莫名认为有病毒&#xff0c;自动删除插件。附图。 2、第一反应是电脑防火墙的原因&#xff0c;默认威胁防护识别到了病毒软件&#xff0c;自动删除。在开始屏幕搜Windows安全中心&#xff0c;打开之后发…

【MQ篇】初识MQ!

目录 一、什么是MQ&#xff1f;简单来说就是个“快递中转站” &#x1f4e6;二、为什么要用MQ&#xff1f;用了它&#xff0c;好处多多&#xff01;&#x1f929;三、MQ的应用场景&#xff1a;各行各业都能用&#xff01;&#x1f30d;四、MQ的优缺点&#xff1a;硬币的两面&am…

2、SpringAI接入ChatGPT与微服务整合

2、SpringAI接入ChatGPT与微服务整合 小薛博客AI 大模型资料 1、SpringAI简介 https://spring.io/projects/spring-ai Spring AI是一个人工智能工程的应用框架。其目标是将Spring生态系统的设计原则&#xff08;如可移植性和模块化设计&#xff09;应用于人工智能领域&#…

榕壹云预约咨询系统:基于ThinkPHP+MySQL+UniApp打造的灵活预约小程序解决方案

数字化咨询场景的痛点与解决方案 在心理咨询、医疗问诊、法律咨询等需要预约服务的场景中&#xff0c;传统线下预约存在效率低、管理复杂、资源分配不均等问题。榕壹云预约咨询系统基于ThinkPHPMySQLUniApp技术栈开发&#xff0c;为咨询类行业提供了一套高效、安全、可扩展的数…

opencv 图像矫正的原理

图像矫正的原理是透视变换&#xff0c;下面来介绍一下透视变换的概念。 听名字有点熟&#xff0c;我们在图像旋转里接触过仿射变换&#xff0c;知道仿射变换是把一个二维坐标系转换到另一个二维坐标系的过程&#xff0c;转换过程坐标点的相对位置和属性不发生变换&#xff0c;…

计算机前沿技术课程论文 K-means算法在图像处理的应用

K-means算法在图像处理的应用 这是本人在计算机前沿技术课程中的课程论文文章&#xff0c;为了方便大家参考学习&#xff0c;我把完整的论文word文档发到了我的资源里&#xff0c;有需要的可以自取。 点击完整资源链接 目录 K-means算法在图像处理的应用摘要&#xff1a;引言1…

WSL2-Ubuntu22.04安装URSim5.21.3

WSL2-Ubuntu22.04安装URSim5.21.3 准备安装启动 准备 名称版本WSL2Ubuntu22.04URSim5.21.3VcXsrvNaN WSL2安装与可视化请见这篇:WSL2-Ubuntu22.04-配置。 安装 我们是wsl2-ubuntu22.04&#xff0c;所以安装Linux版本的URSim&#xff0c;下载之前需要注册一下&#xff0c;即…

blender 录课键位显示插件(图文傻瓜式安装)

1、下载 点击这个链接进行下载https://github.com/nutti/Screencast-Keys 下载好不用解压 2、安装 打开blender进行安装 点击编辑选择偏好设置 选择插件再点击这个下箭头 选择从磁盘安装 然后找到自己刚刚下载好的&#xff0c;点击从磁盘安装 安装完成后勾选上插件 …

天翼云手机断开连接2小时关机

2025-04-21 天翼云手机断开连接2小时自动 天翼云手机 4元1个月 天翼云手机永不关机 天翼云手机不休眠 天翼云手机断开连接时&#xff0c;界面显示&#xff1a;离线运行&#xff0c;2小时后自动关机 电脑每小时自动连接一次 手机每小时自动连接一次

基于 FFmpeg 的音视频处理基础原理与实验探究

目录 1 基本知识1.1 解封装1.2 AAC和ADTS说明 1.3 H2641.3.1 H264编码结构解析1.3.2 NALU1.3.2 分类 2 实验1 探究音视频信息2.1 重要结构体介绍2.2 相关的API 3 实验二 提取AAC数据4 实验三 提取h264 1 基本知识 1.1 解封装 封装的逆向操作&#xff1a;封装是把音频流、视频流…

我用deepseek做了一个提取压缩文件夹下pdf和word文件工具

由于最近需要把大量的压缩文件的pdf和word文件统一复制到一个文件夹中。 我们一般正常操作方式的是把一个压缩文件一个一个解压&#xff0c;然后在把一个的解压好的文件夹下文件复制到另外一个文件夹中。 这个也需太繁琐了&#xff0c;从以往统计的需要花费两个小时间&#x…

机器人进阶---视觉算法(五)仿射变换和投影变换有什么区别

仿射变换和投影变换有什么区别 1. 定义2. 几何特性3. 变换矩阵4. 应用场景5. Python代码示例仿射变换投影变换6. 总结仿射变换和投影变换都是图像处理中常用的几何变换方法,但它们在变换性质、应用场景和变换矩阵等方面存在一些关键区别。 1. 定义 仿射变换 (Affine Transform…

如何在 Amazon EC2 上部署 Java(Spring Boot 版)

让我们学习如何将 Java Spring Boot Web 服务器部署到 Amazon EC2。每月只需 3 美元。 使用 Azure&#xff0c;您可能不知道要花费多少钱。 Spring Boot 项目示例 在本教程中&#xff0c;我们将重点介绍如何将 Java Spring Boot 服务器部署到 Amazon EC2&#xff0c;因此我们不…

IDEA打不开、打开报错

目录 场景异常原因解决 场景 1、本机已经安装了IDEA 2、再次安装另外一个版本的IDEA后打不开、打开报错 异常 这里忘记截图了。。。 原因 情况1-打不开&#xff1a;在同一台电脑安装多个IDEA是需要对idea的配置文件进行调整的&#xff0c;否则打不开 情况2-打开报错&#…

【React】项目的搭建

create-react-app 搭建vite 搭建相关下载 在Vue中搭建项目的步骤&#xff1a;1.首先安装脚手架的环境&#xff0c;2.通过脚手架的指令创建项目 在React中有两种方式去搭建项目&#xff1a;1.和Vue一样&#xff0c;先安装脚手架然后通过脚手架指令搭建&#xff1b;2.npx create-…

CSS例子 > 图片瀑布流布局(vue2)

<template><div class"container"><!-- 临时容器用于计算高度 --><div v-if"!isLayoutReady" class"temp-container"><divv-for"(item, index) in list":key"temp- index":ref"(el) > …

1.2软考系统架构设计师:系统架构的定义与作用 - 练习题附答案及超详细解析

系统架构定义与作用综合知识单选题 题目覆盖核心概念、发展历程、设计原则、评估标准及易混淆点&#xff0c;附答案解析&#xff1a; 1. 系统架构的标准定义源自于以下哪个标准&#xff1f; A. ISO/IEC 9126 B. IEEE 1471-2000 C. TOGAF 9.2 D. ITIL v4 答案&#xff1a;B 简…