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

关于 React Fiber 架构、Hooks 原理

下面将详细介绍你提到的关于 React Fiber 架构、Hooks 原理等相关知识点:

React Fiber 架构概述

1. 架构演变

在 React 16 版本之前,采用的是栈调和(Stack Reconciler),流程是 JSX 经过 render 函数转换为虚拟 DOM(VDOM),然后直接递归渲染 VDOM。这种方式一旦开始渲染就无法中断,若渲染任务复杂,会导致页面卡顿,影响用户体验。

而 React 16 引入了 Fiber 架构,在 VDOM 和实际 DOM 渲染之间增加了一个协调(Reconcile)阶段。在这个阶段,会将 VDOM 转换为 Fiber 节点树,同时进行 Diff 算法比较新旧 VDOM 的差异,并给需要增删改的节点打上 effectTag 标记,最后在提交(Commit)阶段一次性更新到实际 DOM 上。

2. 协调(Reconcile)与调度(Schedule)
  • 协调(Reconcile):该阶段主要完成 VDOM 到 Fiber 节点的转换、Diff 比较以及标记 effectTag。它是可中断的,这意味着 React 可以在执行过程中暂停当前的协调任务,去处理更紧急的任务,如用户的交互事件等,处理完后再恢复之前的协调任务。
  • 调度(Schedule):Fiber 架构的调度机制会根据任务的优先级来安排执行顺序。高优先级的任务(如用户交互)会优先执行,低优先级的任务(如数据获取)可以稍后执行,从而保证页面的流畅性和响应性。

Hooks 原理

1. 基于 Fiber 节点的链表存储

Hooks 的实现依赖于 Fiber 节点。每个 Fiber 节点上有一个链表,链表中的每个节点都有一个 memorizedState 属性,用于存放对应 Hook 的数据。例如,当在组件中多次调用 useState 或其他 Hook 时,它们的数据会依次存储在这个链表中。

2. 挂载(Mount)与更新(Update)阶段

每个 Hook 的实现都分为挂载(mountXxx)和更新(updateXxx)两个阶段:

  • 挂载阶段(mountXxx:在组件首次渲染时,会执行 mountXxx 函数,用于初始化 Hook 的状态和数据,并将其存储在 memorizedState 链表中。
  • 更新阶段(updateXxx:在组件后续的渲染中,会执行 updateXxx 函数,从 memorizedState 链表中获取之前存储的数据,并根据新的情况进行更新。
3. 不同 Hooks 的实现
useRefuseCallbackuseMemo

这些 Hook 主要用于对值进行缓存,逻辑相对简单,不依赖 React 的调度机制。

  • useRef:返回一个可变的 ref 对象,其 .current 属性可以被赋值并保留值。在挂载阶段,会创建一个新的 ref 对象并存储在 memorizedState 中;在更新阶段,直接从 memorizedState 中获取该 ref 对象。
// 简化的 useRef 实现思路
function useRef(initialValue) {let hook;if (isMount) {// 挂载阶段hook = {memorizedState: { current: initialValue }};isMount = false;} else {// 更新阶段hook = nextCurrentHook;}nextCurrentHook = hook.next;return hook.memorizedState;
}
  • useCallback:用于缓存函数,避免在每次渲染时都重新创建函数。在挂载阶段,会将传入的函数存储在 memorizedState 中;在更新阶段,会比较依赖项数组是否发生变化,如果没有变化,则返回之前缓存的函数。
  • useMemo:用于缓存计算结果,避免在每次渲染时都进行重复的计算。其实现原理与 useCallback 类似,只是缓存的是计算结果。
useState

useState 会触发 Fiber 的调度机制。在挂载阶段,会初始化状态并存储在 memorizedState 中;在更新阶段,当调用 setState 函数时,会更新状态并标记当前 Fiber 节点需要重新渲染,从而触发调度器安排新的渲染任务。

// 简化的 useState 实现思路
function useState(initialState) {let hook;if (isMount) {// 挂载阶段hook = {memorizedState: initialState,queue: []};isMount = false;} else {// 更新阶段hook = nextCurrentHook;}const setState = (action) => {hook.queue.push(action);// 触发调度更新scheduleUpdate();};let baseState = hook.memorizedState;hook.queue.forEach(action => {baseState = typeof action === 'function'? action(baseState) : action;});hook.memorizedState = baseState;nextCurrentHook = hook.next;return [baseState, setState];
}
useEffect

useEffect 也有自己的调度逻辑。在挂载阶段,会将副作用函数存储在 memorizedState 中;在更新阶段,会比较依赖项数组是否发生变化,如果发生变化,则会在组件渲染完成后(浏览器绘制屏幕之后)异步执行副作用函数。同时,副作用函数可以返回一个清理函数,用于在组件卸载或下次副作用函数执行之前进行清理操作。

4. 自定义 Hooks

自定义 Hooks 本质上就是一个函数调用,它可以复用其他 Hook 的逻辑。自定义 Hooks 没有特殊的实现机制,只是遵循 Hooks 的规则(如只能在函数组件或其他 Hook 中调用)。Lint 规则用于确保 Hooks 的正确使用,如果不想遵守可以忽略,但可能会导致一些难以调试的问题。

综上所述,Hooks 的原理既有简单的部分(如 useRefuseCallbackuseMemo 等的缓存逻辑),也有复杂的部分(如 useStateuseEffect 涉及的调度逻辑),理解这些原理有助于更好地使用和开发 React 应用。

http://www.xdnf.cn/news/2458.html

相关文章:

  • 机器学习的一百个概念(13)布里尔分数
  • OkHttp源码梳理
  • 数字后端设计 (六):验证——给芯片做「超严格体检」
  • 苍穹外卖(缓存商品、购物车)
  • 基于Qt5的蓝牙打印开发实战:从扫描到小票打印的全流程
  • 关系型数据库PostgreSQL vs MySQL 深度对比:专业术语+白话解析+实战案例
  • Tomcat的安装与配置
  • 高能效计算:破解算力增长与能源约束的科技密码
  • JavaScript 函数与算法性能优化
  • 微软GraphRAG的安装和在RAG中的使用体会
  • Javase 基础入门 —— 06 final + 单例
  • 游戏哪些接口会暴露源IP?_深度解析服务器通信安全隐患
  • Apache Sqoop数据采集问题
  • 极客时光:第二部分——用QLoRA、RunPod和Cursor以超低成本微调DeepSeek-7B打造你的聊天机器人
  • WHAT - 《成为技术领导者》思考题(第二章)
  • 加速用户体验:Amazon CloudFront 实践与优化技巧
  • PDFMathTranslate:让数学公式在PDF翻译中不再痛苦
  • 【Android】dialogX对话框框架
  • 【C++ 类和数据抽象】消息处理示例(2)
  • 《代码整洁之道》第9章 单元测试 - 笔记
  • es数据导出
  • Vue中Axios实战指南:高效网络请求的艺术
  • Excel如何安装使用EPM插件并且汉化?
  • uniapp+vue3表格样式
  • Golang | Builder模式
  • 大模型——Suna集成浏览器操作与数据分析的智能代理
  • Transformer数学推导——Q25 分析视觉-语言模型中区域注意力(Region Attention)的边界框投影公式
  • Ubuntu 22.04.4操作系统初始化详细配置
  • WPF使用SQLite与JSON文本文件结合存储体侧平衡数据的设计与实现
  • 【设计模式】享元模式