当前位置: 首页 > article >正文

调用 useState 之后发生了啥(⊙_⊙)?

在 React 中,useState 是一个 Hook,用于在函数组件中添加和管理状态。当你调用 useState 时,React 会执行一系列步骤来管理状态并确保组件能够正确地重新渲染。以下是详细的解释:

1. 状态初始化
首次渲染:
  • 创建新的状态值:当你首次渲染组件时,useState(initialValue) 会创建一个新的状态值,并将其存储在 React 内部管理的 Hooks 链表中。
  • 函数形式的初始值:如果 initialValue 是一个函数(如 useState(() => 0)),React 会在首次渲染时执行该函数获取初始值(仅在首次渲染时执行一次)。
const [count, setCount] = useState(0); // 初始值为 0
// 或者使用函数形式的初始值
const [count, setCount] = useState(() => computeInitialValue());
后续渲染:
  • 直接返回已存储的状态值:组件重新渲染时,useState 会直接返回链表中已存储的当前状态值,而不会重新初始化。
2. 返回状态与更新函数

useState 返回一个数组,包含两个元素:

  • 当前状态值:从 Hooks 链表中读取的值。
  • 状态更新函数(如 setCount :用于触发状态变更和组件的重新渲染。
const [value, setValue] = useState('初始值');
3. 更新状态与触发渲染
状态变更检查:
  • 当你调用 setValue(newValue) 时,React 会比较新旧值(使用 Object.is 算法)。如果值未变化,不会触发重新渲染。
标记组件为待更新:
  • 如果值发生变化,React 会将组件标记为需要重新渲染,并将其加入更新队列。
批量更新(Batching):
  • 在 React 18+ 中,所有更新(包括事件回调、setTimeout 等)默认自动批处理,合并为一次渲染。
  • 多次连续调用 setValue 可能被合并,例如:
setValue(1);
setValue(2); // 最终直接更新为 2,仅触发一次渲染。
渲染阶段:
  • 在下一次渲染周期中,React 重新执行组件函数,此时 useState 返回最新的状态值。
4. 触发调和过程 (Reconciliation)
调和过程:
  • 在重新渲染过程中,React 生成一个新的虚拟 DOM 树,并将其与之前的虚拟 DOM 树进行比较。
  • 这个过程称为“调和”(Reconciliation),其目的是高效地计算出哪些部分需要更新。
差异计算:
  • React 使用一种称为“差异算法”(Diffing Algorithm)的技术来高效地计算新旧虚拟 DOM 树之间的差异。
  • 通过这种算法,React 可以精确地知道哪些节点发生了变化以及应该如何更新这些节点,从而实现最小化重渲染。
最小化重渲染:
  • 基于差异计算的结果,React 只对那些实际发生变化的部分进行更新,而不是整个页面。
  • 这种按需更新的方式可以显著提高性能,特别是在大型应用中。

具体步骤详解

  1. 状态初始化与存储

    • 首次渲染时,useState(initialValue) 初始化状态,并将其存储在 React 的内部 Hooks 链表中。
    • 如果 initialValue 是一个函数,React 会在首次渲染时执行该函数获取初始值。
  2. 返回状态与更新函数

    • useState 返回一个数组 [currentState, setState],其中 currentState 是当前状态值,setState 是更新状态的函数。
  3. 调用 setState 更新状态

    • 当你调用 setState(newValue) 时,React 会将新的状态值放入更新队列中,并在合适的时机批量处理这些更新。
    • React 使用 Object.is 算法比较新旧状态值,如果值未变化,则不会触发重新渲染。
  4. 调度更新

    • React 不会立即执行状态更新和重新渲染,而是将这些更新请求放入队列,并在合适的时机批量处理它们。
    • 在 React 18+ 中,默认启用了批处理(Batching),这意味着多次连续的状态更新可能会被合并为一次渲染。
  5. 触发调和过程

    • React 生成新的虚拟 DOM 树,反映最新的 UI 状态。
    • React 比较新旧虚拟 DOM 树之间的差异,确定哪些部分需要更新。
  6. 差异计算与最小化重渲染

    • React 计算新旧虚拟 DOM 树之间的差异,基于差异计算的结果,React 只对那些实际发生变化的部分进行更新,而不是整个页面。

以下是一个完整的示例,展示了如何使用 useState 并解释其背后的流程:

import React, { useState } from "react";
import { Button } from "antd";

const DateModule = () => {
  // 使用 useState 钩子初始化状态
  const [value, setValue] = useState('初始值');

  return (
    <>
      {/* 显示当前的 value */}
      <p>{value}</p>
      
      {/* 按钮点击时调用 setValue 更新 value */}
      <Button onClick={() => setValue('new Value')}>按钮</Button>
    </>
  );
};

export default DateModule;

总结

调用 useState 并更新状态后,React 会经历以下几个关键步骤:

  1. 状态初始化:首次渲染时,useState 创建并存储状态值;后续渲染时,直接返回存储的状态值。
  2. 返回状态与更新函数useState 返回当前状态值和更新状态的函数。
  3. 更新状态与调度:调用更新函数(如 setValue)时,React 将新的状态值放入更新队列,并在合适的时机批量处理这些更新。
  4. 触发调和过程:React 生成新的虚拟 DOM 树,并准备重新渲染。
  5. 差异计算与最小化重渲染:React 计算新旧虚拟 DOM 树之间的差异,并只对那些实际发生变化的部分进行更新。

通过这种方式,React 实现了高效的 UI 更新,确保应用在状态变化时能够快速响应且保持高性能。同时,通过批处理和异步更新机制,React 进一步优化了性能,减少了不必要的渲染操作。


http://www.kler.cn/a/538556.html

相关文章:

  • 力扣hot100刷题第一天
  • 什么是中间件中间件有哪些
  • 开放式TCP/IP通信
  • 【Ubuntu】安装和使用Ollama的报错处理集合
  • 深度求索(DeepSeek)的AI革命:NLP、CV与智能应用的技术跃迁
  • 计算机网络应用层:模型、系统与协议全解析!!!
  • windows蓝牙驱动开发-蓝牙无线电重置和恢复
  • cpp之模板
  • 安装和使用 Ollama(实验环境windows)
  • 2月7日QT
  • c/c++蓝桥杯经典编程题100道(16)链表反转
  • 面试经典150题——字典树
  • Deepseek本地部署指南:在linux服务器部署,在mac远程web-ui访问
  • 基于开源AI智能名片2+1链动模式S2B2C商城小程序的个人IP活动运营策略与影响力提升研究
  • LangChain + DeepSeek-R1:构建高效的语言模型服务
  • Qt+海康虚拟相机的调试
  • 调用Jenkins接口api的几个例子
  • 【R语言】数据重塑
  • 什么是ZooKeeper?
  • 前端开发中遇到的小问题以及解决方案记录3
  • 使用GD32F470的硬件SPI读写W25Q64
  • mysql 库建表数量有限制吗?
  • C语言时间相关宏定义
  • 并发编程 - 线程同步(五)之原子操作Interlocked详解二
  • C语言【基础篇】之数组——解锁多维与动态数组的编程奥秘
  • ASP.NET Core 使用 WebClient 从 URL 下载