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

React useState原理解密:从源码到实战

简介

useState是React Hooks的核心之一,理解它的底层原理有助于更好地是使用它。

基本数据结构

React内部使用单向链表管理Hooks。每个组件都有一个对应地fiber对象,其中包含一个memoizedState属性来存储hooks链表

// 简化的 Hook 结构
const hook = {memoizedState: null, // 存储当前状态值baseState: null,     // 基础状态queue: null,         // 更新队列next: null           // 指向下一个 hook
};

工作流程

  1. 组件首次渲染时,React会按顺序创建hooks链表
  2. useState接受地初始值会被存入memoizedState中(惰性初始化:只有在初次渲染的时候才执行一次)
  3. 调用setState时,更新会被加入队列
  4. 下次渲染的时候,React会处理队列中的所有更新
// 伪代码展示更新
function dispatchAction(queue, action) {const update = { action, next: null };// 将更新加入队列if (queue.pending === null) {update.next = update; // 自引用形成循环链表} else {// 跟新队列插入updateupdate.next = queue.pending.next;queue.pending.next = update;}queue.pending = update;// 触发重新渲染scheduleWork();
}
// 伪代码展示初始化
function mountState(initialState) {const hook = mountWorkInProgressHook();// 创建hook// 初始化memoizedStatehook.memoizedState = typeof initialState === 'function' ? initialState() : initialState;// 初始化更新队列const queue = { pending: null };hook.queue = queue;// 包装更新队列const dispatch = dispatchAction.bind(null, queue);return [hook.memoizedState, dispatch];
}

关键实现细节

状态合并

多个状态更新会被批量处理​(React 17及之前版本在事件处理函数中批量处理,React 18+自动批量处理所有更新)

function Example() {const [count, setCount] = useState(0);const handleClick = () => {setCount(c => c + 1); // 不会立即更新setCount(c => c + 1); // 会与前一个合并// 最终 count 只会增加 2,而不是触发两次渲染};
}

闭包陷阱

由于函数组件的特性,每次渲染都有自己的 props 和 state,但是闭包特性又有可能导致状态值”卡住“地现象,特别是在异步操作和时间处理中常见,这就是闭包陷阱。

function Counter() {const [count, setCount] = useState(0);useEffect(() => {const timer = setInterval(() => {console.log(count); // 总是打印初始值,形成闭包陷阱}, 1000);return () => clearInterval(timer);}, []); // 空依赖数组return <div>{count}</div>;
}

更新调度

React 使用调度器(Scheduler)来决定何时处理状态更新,这使 React 能够:

  1. 优先处理高优先级更新
  2. 在浏览器空闲时执行低优先级更新
  3. 避免阻塞主线程

简易实现

下面是一个极简版的 useState 实现,帮助理解核心原理:

let currentHook = 0; // 当前 hook 的索引
let hooks = [];      // 存储所有 hookfunction useState(initialState) {const position = currentHook++;// 初始化时设置初始状态if (hooks[position] === undefined) {hooks[position] = typeof initialState === 'function' ? initialState() : initialState;}// 返回当前状态和更新函数return [hooks[position],(newState) => {hooks[position] = typeof newState === 'function'? newState(hooks[position]): newState;// 这里应该触发组件重新渲染render();}];
}// 组件渲染前重置 hook 索引
function render() {currentHook = 0;// 实际渲染逻辑...
}

与类组件setState的区别

特性** useState**** 类组件 setState**
更新方式替换式更新合并式更新
异步行为总是异步在生命周期和事件处理中异步
多个状态需要多个useState 单个 state 对象
性能优化依赖数组shouldComponentUpdate
获取前一个状态使用函数式更新接收 prevState 参数

结语

本篇文章可以帮助你理解以下问题:

  • 避免常见的陷阱(如闭包问题)
  • 写出更高效的组件
  • 更好的调试状态相关问题
  • 理解React的更新机制
http://www.xdnf.cn/news/15367.html

相关文章:

  • 苍穹外卖-day06
  • JavaScript代码段注入:动态抓取DOM元素的原理与实践
  • 巅峰对决:文心4.5 vs DeepSeek R1 vs 通义Qwen3.0——国产大模型技术路线与场景能力深度横评
  • Python-魔术方法-创建、初始化与销毁-hash-bool-可视化-运算符重载-容器和大小-可调用对象-上下文管理-反射-描述器-二分-学习笔记
  • 代码训练LeetCode(46)旋转图像
  • Java应用全链路故障排查实战指南:从系统资源到JVM深度诊断
  • 基于定制开发开源AI智能名片S2B2C商城小程序的社群游戏定制策略研究
  • 不止于监控:深入剖析OpenTelemetry的可观察性生态体系
  • 江协科技STM32入门教程——通信接口
  • Web安全-Linux基础-02-系统基础命令
  • QCustomPlot绘制交互图
  • VUE3 el-table 主子表 显示
  • 【极客日常】后端任务动态注入执行策略的一种技术实现
  • 解决bash终端的路径名称乱码问题
  • Spring之【写一个简单的IOC容器EasySpring】
  • 批量自动运行多个 Jupyter Notebook 文件的方法!!!
  • 创建Spring Boot项目
  • 基于 Redisson 实现分布式系统下的接口限流
  • 网络安全初级第一次作业
  • MacOS环境下运行EasySearch报错无法信任Java包的解决方案
  • ServiceNow Portal前端页面实战讲解
  • GGE Lua 详细教程
  • 【6.1.1 漫画分库分表】
  • c#中生成随机数的三种方法
  • pgsql模板是什么?
  • Kafka——聊聊Kafka的版本号
  • 【理念●体系】从零打造 Windows + WSL + Docker + Anaconda + PyCharm 的 AI 全链路开发体系
  • 1Panel V1 无缝升级到 V2 版本 实现多个 PHP 网站共享一个容器
  • Spring Boot整合MyBatis+MySQL实战指南(Java 1.8 + 单元测试)
  • AIStarter新版重磅来袭!永久订阅限时福利抢先看