深度解析react中hooks的底层原理是啥?React架构原理深度解析

1.React Hooks 底层原理

React Hooks 的底层原理是基于 React Fiber 架构的实现。下面是对 React Hooks 底层原理的深度解析:

  1. Fiber 架构 : React Fiber 是 React 的新的协调引擎,它的设计目标是支持增量式更新优先级调度暂停和继续执行等特性。Fiber 架构重新实现了 React 的调度算法,使得 React 可以更灵活地控制组件的渲染过程。

    我们都知道react框架的核心算法是diff算法的,其实 diff 算法的核心就是复用节点,通过一一对比也好,通过 map 查找也好,都是为了找到可复用的节点,移动过来。然后剩下的该删删该增增。在 16 之后,为了优化性能,会先把 vdom 转换成 fiber,也就是从树转换成链表,然后再渲染。整体渲染流程分成了两个阶段:

    render 阶段 :从 vdom 转换成 fiber,并且对需要 dom 操作的节点打上 effectTag 的标记 commit 阶段:对有 effectTag 标记的 fiber 节点进行 dom 操作,并执行所有的 effect 副作用函数。

从 vdom 转成 fiber 的过程叫做 reconcile(调和),这个过程是可以打断的,由 scheduler 调度执行。第一次渲染不需要 diff,直接 vdom 转 fiber。再次渲染的时候,会产生新的 vdom,这时候要和之前的 fiber 做下对比,决定怎么产生新的 fiber,对可复用的节点打上修改的标记,剩余的旧节点打上删除标记,新节点打上新增标记。

  1. Hooks 的调度和状态管理 : React Hooks 的核心思想是在函数组件中引入状态和副作用的管理。Hooks 的使用不依赖于 class 组件,它们是通过调用 React 内部的底层 API 来实现的。Hooks 在函数组件中引入了 useStateuseEffectuseReducer 等钩子函数,这些钩子函数允许在函数组件中使用状态和副作用。

  2. Hooks 实现原理: Hooks 的实现基于 React Fiber 的调度机制和组件树的遍历。当函数组件被调用时,React 会创建一个 Fiber 节点来表示该组件,并将其添加到 Fiber 树中。Hooks 的状态管理和副作用逻辑被存储在 Fiber 节点中,并在组件的每次渲染中被调用。

  3. Hooks 的规则: React Hooks 有一些规则和约束,这些规则保证了 Hooks 的正确使用和执行顺序:

    • Hooks 只能在函数组件的顶层使用,不能在循环、条件语句或嵌套函数中使用。
    • Hooks 的调用顺序必须保持一致,不能在条件语句中或循环中调用 Hooks。
    • Hooks 的调用不能出现在任何 JavaScript 函数中,而是在 React 函数组件中调用。
  4. Hooks 的优势

    • 使函数组件具备了状态和副作用管理的能力,不再依赖于类组件。
    • 更容易共享状态逻辑,实现逻辑的复用。
    • 使得 React 组件更加简洁和易于理解。

总的来说,React Hooks 的底层原理是基于 Fiber 架构的调度机制和组件树的遍历实现的。Hooks 通过调用 React 内部的底层 API 来实现状态和副作用的管理,并通过一系列规则保证了 Hooks 的正确使用。Hooks 的出现使得函数组件具备了类组件的功能,使得 React 的组件编写更加灵活和高效。

2.接下来接着谈谈 Fiber 架构

React Fiber 是一种基于协程的实现,用于实现异步渲染和任务优先级调度。这里我们讲一下协程的概念:协程是一种控制流程让出机制,配合线程实现并发能力。

Fiber 架构的核心目标是实现增量渲染和优先级调度,每个 Fiber 可以被看作是一个执行单元,表示了组件树中的一个小部分,负责管理自身对应的组件和其渲染过程。

通过引入协程的概念,React Fiber 实现了任务的切片和中断与恢复,使得 React 能够更高效地处理渲染任务和异步任务,使得 React 应用在处理大量元素或者复杂交互时能够更好地响应用户操作,并避免阻塞主线程,从而提高应用的性能和用户体验。

以下是 React Fiber 架构的主要特点和实现原理:

  1. 增量渲染: Fiber 架构将渲染过程划分为多个小任务(Fiber),并使用协作式调度的方式执行这些任务。它允许 React 在执行任务的过程中中断和恢复,从而使得页面的渲染过程成为可中断的,可以在多个帧中完成,提高了用户界面的响应速度。

  2. 优先级调度: Fiber 架构引入了任务优先级的概念,不同任务可以具有不同的优先级,React 可以根据优先级来决定哪些任务应该优先执行,从而确保页面的交互和动画在高优先级任务的影响下得到及时更新,而低优先级任务则可以在后台或空闲时执行,以保证用户体验的流畅性。

  3. 可中断性和恢复性: Fiber 架构使得渲染过程中的任务可以被中断,并在稍后恢复执行。这种可中断性和恢复性使得 React 应用可以更好地响应用户操作和浏览器的优先级调度,避免了长时间的任务阻塞主线程,提高了应用的性能和流畅度。

  4. 双缓存渲染: Fiber 架构采用了双缓存渲染技术,即同时维护两棵虚拟 DOM 树,一棵用于渲染当前页面,另一棵用于在后台进行更新。当更新完成后,React 会切换到新的虚拟 DOM 树,从而避免了页面渲染过程中的闪烁和不一致性。

  5. 增加任务调度器: Fiber 架构引入了任务调度器(Scheduler),负责协调和调度任务的执行顺序和优先级。任务调度器会根据任务的优先级来决定何时执行任务,并允许任务之间相互中断和恢复执行。

3.fiber是怎么实现任务的切片和中断与恢复?

利用sheduler实现任务调度的优先级划分处理,同时看看浏览器的剩余任务处理时间是否有空闲,有时间就处理,没有时间就暂停等待下一轮时间的分配。具体来说,Fiber的任务切片、中断和恢复的过程如下:

任务切片:当React开始执行一个任务(比如渲染组件树)时,它会将任务分割成多个小的执行单元,即fiber。这些fiber表示组件树中的每个组件,每个fiber包含了组件的状态、props、子fiber等信息。

中断:在执行每个fiber时,React会检查是否需要中断当前的任务。中断的条件包括时间片过期、有更高优先级的任务等。如果需要中断,React会将当前的fiber标记为中断状态,并将控制权交还给调度器。

恢复:当下一次调度发生时,调度器会根据优先级选择合适的fiber继续执行。React会从中断的位置恢复执行,继续处理剩下的fiber。这样就实现了任务的中断和恢复。

以下是一个简单的示例代码,展示了Fiber如何实现任务切片、中断和恢复:

javascript 复制代码
function render() {
  // 执行根fiber的渲染任务
  performUnitOfWork(rootFiber);
}

function performUnitOfWork(fiber) {
  // 执行当前fiber的任务
  // ...

  if (有更高优先级任务) {
    // 中断当前任务,将控制权交还给调度器
    scheduleInterrupt(fiber);
    return;
  }

  if (还有子fiber) {
    // 执行子fiber的任务
    performUnitOfWork(childFiber);
  }

  // 没有子fiber,向上遍历兄弟fiber
  while (无兄弟fiber && 有父fiber) {
    // 返回父fiber,继续执行父fiber的任务
    fiber = fiber.parent;
  }

  if (有兄弟fiber) {
    // 执行兄弟fiber的任务
    performUnitOfWork(siblingFiber);
  } else {
    // 所有fiber任务都完成,提交更新
    commitRoot();
  }
}

function scheduleInterrupt(fiber) {
  // 将fiber标记为中断状态
  fiber.interrupted = true;

  // 将fiber加入调度队列,等待下一次调度
  scheduleWork();
}

function scheduleWork() {
  // 根据优先级选择合适的fiber继续执行
  // ...
}

function commitRoot() {
  // 提交更新到DOM
  // ...
}

function handleClick() {
  // 中断当前任务,响应用户点击事件
  scheduleInterrupt(currentFiber);
  // ...
}

在上面的代码中,render()函数触发了根fiber的渲染任务,然后调用performUnitOfWork()函数开始执行任务。在执行每个fiber的任务时,会检查是否有更高优先级的任务,如果有,则中断当前任务,将控制权交还给调度器。调度器会根据优先级选择合适的fiber继续执行。

当中断发生时,可以通过用户交互等方式触发,比如handleClick()函数中的用户点击事件。在中断时,调用scheduleInterrupt()函数将当前fiber标记为中断状态,并将其加入调度队列,等待下一次调度。

在下一次调度发生时,调度器会根据优先级选择合适的fiber继续执行,从中断的位置恢复执行。这样就实现了任务的中断和恢复。

注意:上述代码只是简化的示例,实际的Fiber实现更加复杂和庞大。以上代码仅用于说明Fiber中任务切片、中断和恢复的基本原理,具体实现还包括对优先级的处理、任务调度策略的设计等。

最后但也是全文最重要的,码字不易,你的鼓励是我持之以恒创作的动力,欢迎点赞关注加搜藏!!!!感谢感谢感谢。

相关推荐
安冬的码畜日常42 分钟前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
小白学习日记2 小时前
【复习】HTML常用标签<table>
前端·html
丁总学Java2 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele2 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
懒羊羊大王呀2 小时前
CSS——属性值计算
前端·css
DOKE3 小时前
VSCode终端:提升命令行使用体验
前端
xgq3 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
用户3157476081353 小时前
前端之路-了解原型和原型链
前端
永远不打烊3 小时前
librtmp 原生API做直播推流
前端