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

关于 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 应用。

相关文章:

  • Python爬虫(8)Python数据存储实战:JSON文件读写与复杂结构化数据处理指南
  • pycharm无法创建venv虚拟环境
  • 大模型图像编辑那家强?
  • Centos8 安装 Docker
  • ​​全栈自动化:从零构建智能CI/CD流水线​
  • 多模态常见面试题
  • HTML倒数
  • 使用 MediaPipe 和 OpenCV 快速生成人脸掩膜(Face Mask)
  • 为什么选择 Spring Boot? 它是如何简化单个微服务的创建、配置和部署的?
  • PROXY_ARP在CALICO网络中的应用
  • OpenCV进阶操作:图像金字塔
  • rt-linux下的cgroup cpu的死锁bug
  • 解决SSLError: [SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC] decryption faile的问题
  • 【AI模型学习】GPT——从v1到v3
  • 微软GraphRAG的安装和在RAG中的使用体会
  • 安卓7.0以上抓包配置--Charles
  • 技能点总结
  • Android四大核心组件
  • 数据结构——二叉树和堆(万字,最详细)
  • Day 12
  • 新一届中国女排亮相,奥运冠军龚翔宇担任队长
  • 外交部:对伊朗拉贾伊港口爆炸事件遇难者表示深切哀悼
  • 中消协发布“五一”消费提示:践行“光盘行动”,抵制餐饮浪费
  • 科学时代重读“老子”的意义——对谈《老子智慧八十一讲》
  • 国家发改委答澎湃:将指导限购城市针对长期摇号家庭和无车家庭等重点群体定向增发购车指标
  • AI应用大盘点:谁暴涨?谁掉队?