1. React18有哪些更新?React 18 带来了许多新特性 , 尤其是为了提升性能和用户体验 , 主要更新包括:
- 自动批处理 (Automatic Batching)
React 18 引入了自动批处理的概念 。 以前 , React 只能在事件处理函数中自动批处理状态更新;而在 React 18 中 , 即使在异步函数中 , 比如 setTimeout 或 Promise 回调中 , 也会自动批处理多个状态更新 , 减少了重新渲染次数 , 提高了性能 。
function handleClick() { setTimeout(() => {setState1((prev) => prev + 1);setState2((prev) => prev + 1);1000);
在 React 18 中 , setState1 和 setState2 会在一个批处理中进行更新 , 只会导致一次重新渲染 。- 并发特性 (Concurrent Features)
并发特性允许 React 中断和恢复渲染的能力 , 可以更好地响应用户交互 。 虽然并发特性是 opt-in 的(需要使用 ConcurrentMode) , 但新的 startTransition API 可以显式标记一些非紧急的更新 , React 会在空闲时处理这些更新而不会阻塞主线程 。
import { startTransitionfrom 'react';function handleInputChange(e) { startTransition(() => {setInput(e.target.value); );
- <Suspense> 支持服务端渲染 (SSR Support for \\Suspense)
React 18 对服务端渲染中的 <Suspense> 组件提供了支持 。 在新的 SSR 架构下 , React 可以在加载完部分内容后就开始流式地返回 HTML 片段 , 不需要等到所有内容加载完毕 , 有助于提升首屏加载速度 。 - 新的 Hook:useTransition 和 useDeferredValue
- useTransition:用于处理非紧急状态更新 。 例如 , 输入框内容更新是紧急的 , 而搜索建议的更新可以延迟 。
- useDeferredValue:将某个值标记为可以延迟的值 , 从而在高频率的操作(如输入)中不会导致卡顿 。
- createRoot API
React 18 推荐使用 createRoot 替代 ReactDOM.render 来渲染根组件 , 从而启用并发模式 。
import { createRootfrom 'react-dom/client';const root = createRoot(document.getElementById('root'));root.render(<App />);
- Strict Mode 更严格的行为
React 18 中的 StrictMode 会对某些生命周期方法(例如 useEffect 的回调函数)进行双重调用 , 以帮助开发者检测潜在的副作用问题 , 提高应用的健壮性 。 - 优化的服务端渲染 (SSR)
React 18 中 SSR 支持 React.lazy 和 <Suspense> , 结合流式渲染和延迟组件的加载 , 使得服务器渲染速度更快 , 首屏渲染时间减少 。
1.批处理更新队列
React 会在内部维护一个“批量更新队列” , 在队列内的所有状态更新将合并成一个渲染操作 。 React 会监听各种事件 , 如同步事件(如点击事件)或异步事件(如 setTimeout、Promise 回调等) , 并在合适的时机将更新推送到更新队列中 。
2.事件优先级调度
React 18 引入了并发特性 , 为不同的更新分配了优先级 。 更新被分为同步和非同步更新:
- 同步更新:通常用于用户交互 , 如输入框内容变化 。
- 非同步更新:常用于不紧急的渲染任务 , 如网络请求完成后的数据渲染 。
3.Scheduler调度器
React 18 采用了 Scheduler 调度库(Facebook 开源的调度库) , 用于自动批处理和任务调度 。 该调度器提供了一个“任务优先级”系统 , 允许 React 在需要时可以暂停、恢复、重新开始甚至放弃任务 。 Scheduler 会在每个事件循环末尾检测是否有批处理任务队列存在 , 如果有 , 则执行队列中的任务 。
4.自动批处理触发时机
- 事件回调中的更新:React 在事件回调(如点击、输入)中会默认启动批处理机制 。
- 异步任务中的更新:在 React 18 中 , 即使是在异步任务(如 setTimeout、Promise 回调)中 , React 也会自动启动批处理机制 。 即所有更新在事件循环结束前不会立即触发重新渲染 , 而是会等待异步操作完成后 , 再将多个更新一次性推送到批处理队列中 。
虽然 React 18 默认自动批处理 , 但开发者可以使用 flushSync 函数强制同步更新 , 这将立即触发更新并跳过批处理 。
实现流程简述
- React 检测到状态更新时 , 判断是否处于批处理上下文中 。
- 若是批处理上下文 , React 将状态更新添加到批量更新队列 , 而不立即触发重渲染 。
- 当批处理上下文结束时(通常是当前事件循环结束) , React 将合并状态更新并执行一次重新渲染 。
1.Fiber 架构
React 16 引入的 Fiber 架构 重新设计了 React 的渲染流程 , 使任务可以分段完成 。 Fiber 的核心思想是将渲染任务切割为小的、可以被打断的“单元” , 这些小单元称为 Fiber , 并通过以下几个机制来管理它们:
- 可中断渲染:Fiber 架构将渲染过程分为多个小的任务块 , 允许在每一块任务完成后暂停 , 检查是否有更高优先级的任务需要处理 。
- 任务恢复:React 可以在任务被打断后恢复渲染 , 以便继续之前的渲染进度 , 避免重新开始 。
- 任务丢弃和重启:在某些情况下 , 如果任务中断时间过长 , React 可能会放弃当前的任务 , 重新开始渲染 。
React 并发渲染的一个关键部分是 Scheduler 调度器 , 它基于任务优先级来处理渲染任务 。 Scheduler 根据任务的紧急程度将它们划分为不同优先级:
- 立即优先级:如用户交互操作 , 点击按钮或输入内容 。
- 高优先级:如影响应用功能的状态更新 。
- 正常优先级:如普通的组件更新 。
- 低优先级:如非关键内容的更新 。
- 空闲优先级:仅在浏览器空闲时才执行的任务 。
3.Concurrent Mode 并发模式
React 并发模式并不自动启用 , 只有在使用 createRoot API 时 , 应用才会进入并发模式 。 启用并发模式后 , React 便会通过 Fiber 和 Scheduler 实现以下机制:
- 时间切片(Time Slicing):将长时间任务拆分成可中断的多个时间片 , 让出浏览器主线程 , 允许用户交互流畅执行 。
- startTransition API:在非紧急任务中 , 可以通过 startTransition 将任务标记为低优先级 , 让 React 在有空闲时间时再执行这些任务 。
- useTransition 和 useDeferredValue:这两个 Hook 允许开发者在状态更新中灵活地管理紧急和非紧急任务 , 进一步增强了并发渲染的控制 。
React 并发渲染会先在内存中创建一个新的 UI 树(称为 work-in-progress tree) , 并在渲染完成后再替换原始的 UI 树 。 这一技术确保了更新不会直接影响页面上的实际 DOM 结构 , 减少了不必要的重排和重绘 , 从而提升性能 。
总结
React 18 的并发特性通过 Fiber 架构拆分任务、Scheduler 调度优先级和时间切片来实现 。 这使得 React 可以优先处理紧急任务 , 并在后台低优先级处理非关键任务 , 为用户提供流畅、响应迅速的体验 。
4. React<Suspense>实现原理?React 中的 <Suspense> 是用于处理异步渲染的一个关键组件 , 它允许 React 在等待异步数据加载完成之前 , 展示一个备用的“占位”UI(例如 loading 状态) , 提升用户体验 。 以下是 <Suspense> 的核心实现原理:
1.协同异步渲染:基于 Fiber 架构的中断和恢复
React 使用 Fiber 架构使渲染过程可以被拆解成可中断、恢复的小任务单元(即 Fiber) 。 在加载数据或等待异步任务时 , React 可以暂停渲染 , 显示 <Suspense> 的占位内容(如 loading) , 而不是让整个 UI 停滞等待数据 。
2.Promise暂停渲染
<Suspense> 实现的关键在于使用 Promise 来暂停渲染 。 当 React 渲染一个依赖于异步数据的组件(如使用 React.lazy 动态加载组件或某个数据加载 hook)时 , 该组件会返回一个 Promise 来表示数据的加载状态 。 React 会“捕获”到这个 Promise , 并在其未完成时暂停渲染 。
- 当 React 检测到未完成的 Promise 时 , 会暂停该组件及其子组件的渲染 , 转而显示 <Suspense fallback> 提供的占位内容 。
- 当 Promise 解析(即数据加载完成)时 , React 会继续恢复渲染之前暂停的组件 。
<Suspense> 会利用错误边界机制来“捕获”异步加载状态 。 React 内部会抛出一个特殊类型的错误来表示“异步数据加载中”的状态 。 这个错误并不会导致真正的异常 , 而是通知 React 当前组件的渲染需要暂停 , 等待数据加载完成 。
- React 的错误边界机制会“捕获”这个异常 , 暂停渲染并显示 <Suspense> 的备用 UI 。
- 当 Promise 完成后 , React 将捕获到的异常“恢复” , 继续未完成的渲染 。
当异步任务完成时 , React 会重试被暂停的渲染进程 。 数据加载完成后的组件会重新触发渲染 , 这一过程由 Promise 的完成状态触发 。
- 在每次渲染恢复时 , React 会检查是否有新的 Promise 被触发 。
- 如果没有 , 则完成渲染流程;否则会重复暂停-恢复过程 。
在并发模式下 , <Suspense> 更为高效 。 因为并发模式可以在渲染过程中进行任务切片 , React 可以在异步任务等待时暂停渲染、展示占位内容并响应用户交互 。 并发模式与 <Suspense> 配合得更好 , 提供了一种更流畅的加载体验 。
6.实际使用中的Suspense示例:React.lazy和数据加载
- React.lazy 动态导入:React.lazy 配合 <Suspense> 使用时 , 加载异步组件返回一个 Promise , 并使用 <Suspense> 渲染 loading 占位符 , 等加载完成后再展示组件内容 。
- 数据加载:在数据加载场景中 , 通过 useEffect 或其他数据请求方法返回的 Promise 可以控制 <Suspense> 展示占位符状态 , 在数据加载完成后更新状态以恢复渲染 。
多个嵌套的 <Suspense> 组件可以分别管理不同区域的加载状态 。 React 会选择最近的 <Suspense> 作为占位符展示层级 , 以此实现不同区域的异步渲染和独立加载状态管理 。
总结
<Suspense> 的实现基于 Fiber 架构对任务的中断和恢复 , 利用 Promise 来暂停渲染并配合错误边界来触发备用 UI 。 其通过调度机制和并发模式支持 , 使 React 可以流畅地管理数据加载和组件延迟加载 。
5. useTransition 和 useDeferredValue实现原理?useTransition 和 useDeferredValue 是 React 18 中新增的两个 Hook , 用于更精细地控制异步渲染和任务优先级 。 它们依赖于 React 的并发特性和调度机制 , 通过标记任务的优先级 , 提升应用的交互体验 。 以下是它们的实现原理:
1.useTransition的实现原理
useTransition 是用于将某些状态更新标记为非紧急更新的 Hook , 使这些更新在后台异步执行 , 不会阻塞用户的交互 。
- 基本用法:useTransition 返回一个布尔值(isPending)和一个函数(startTransition) 。 startTransition 会将更新标记为“过渡性任务” , 使得 React 在处理这些更新时可以优先考虑其他更紧急的任务 。
const [isPending startTransition
= useTransition();function handleClick() { startTransition(() => {// 此更新会被标记为非紧急setSomeState(newState); );
- 优先级调度:React 通过内部的 Scheduler 将 startTransition 中的更新标记为“低优先级” , 并将用户的交互更新(如输入或点击)标记为“高优先级” 。 当 React 检测到有更高优先级的任务时 , 会暂停低优先级任务 , 确保用户的高优先级交互能够快速响应 。
- 渲染阶段切分:当 startTransition 包含的更新被推入到任务队列时 , React 会使用“时间切片”技术 , 将任务分成多个时间片并行处理 , 以便在浏览器空闲时执行低优先级任务 , 从而避免因较长渲染任务造成的卡顿现象 。
- isPending 状态:isPending 是一个状态标记 , 它告诉组件当前是否有被延迟的任务 , 方便在渲染过程中提供反馈 。 例如 , 可以用它来显示“加载中”或其他过渡状态的提示 。
useDeferredValue 允许将某个值延迟更新 , 以避免其对渲染性能的影响 , 特别适合用于频繁变化但无需立即更新的值 。
- 基本用法:useDeferredValue 接收一个值作为参数 , 并返回一个“延迟版本”的值 。 React 会将此延迟值视为低优先级的更新 , 确保在浏览器空闲时才更新 。
const deferredSearchTerm = useDeferredValue(searchTerm);
- 优先级管理:React 会根据当前任务的优先级决定 deferredSearchTerm 的更新时机 。 如果其他更高优先级的任务正在进行 , deferredSearchTerm 会保持旧值不变 , 直到高优先级任务完成后再更新 。 这样可以减少渲染频率 , 提高应用的响应速度 。
- 适用场景:例如在搜索组件中 , 输入框的内容可以立即更新 , 但展示的搜索结果可以延迟 。 这种情况下 , 通过 useDeferredValue 将输入的搜索值延迟更新到结果组件上 , 可以避免频繁的数据请求和渲染 , 提升性能 。
- 时间切片(Time Slicing):这两者都依赖于 React 的时间切片机制 。 React 将渲染过程分成多个时间片 , 在每个时间片结束后 , React 可以暂停渲染、检查是否有更高优先级的任务 , 并根据任务优先级动态调整渲染策略 。
- 任务调度(Task Scheduling):Scheduler 会将 startTransition 和 useDeferredValue 的更新标记为低优先级 , 使它们能够在空闲时执行 。 它们的区别在于 , useTransition 延迟整个更新过程 , 而 useDeferredValue 只延迟特定值的更新 。
- useTransition 适用于将特定更新标记为低优先级 , 通常用于触发大范围状态变化(如页面切换、复杂组件加载等) , 不影响用户的直接交互 。
- useDeferredValue 则是将一个特定的值延迟更新 , 适用于频繁变化的输入值 , 避免频繁渲染 , 提升性能 。
6. createRoot API实现原理?createRoot 是 React 18 中引入的 API , 用于创建根节点并启用 React 的并发模式 。 它允许 React 在渲染过程中通过任务切片(Time Slicing)、调度优先级等机制 , 优化渲染性能 , 提升应用的交互体验 。 以下是 createRoot 的实现原理:
1.Fiber 树与并发模式的启动
React 的核心架构是 Fiber , 它将整个渲染过程拆分为小的、可中断的任务单元 。 createRoot 的主要功能之一是启用并发模式(Concurrent Mode) , 在并发模式下 , React 能够更好地调度和分配渲染任务 , 使得渲染可以在后台分片进行 。
- Fiber 树创建:当 createRoot 被调用时 , React 会生成一个新的 Fiber 根节点(Root Fiber) , 并将应用的根组件作为其子节点 。
- 并发渲染启用:与 React 17 中的 ReactDOM.render 方法不同 , createRoot 启用并发渲染 , 使得渲染过程可以被暂停和恢复 , 从而允许 React 在任务执行过程中动态调整优先级 。
在并发模式下 , React 使用 Scheduler(调度器)为每个任务分配优先级 。 不同优先级的任务在渲染中被处理的顺序也不同 , createRoot 启用的并发模式能够让 React 根据任务优先级智能调度渲染过程 。
- 时间切片:通过时间切片技术 , React 可以将渲染过程分割成多个小的时间块 , 在每个时间块结束时检查是否有更高优先级的任务需要执行 。 这样可以在保持流畅渲染的同时 , 不阻塞用户的交互操作 。
- 优先级分类:createRoot 配合 Scheduler , 会为任务分配不同的优先级 , 例如“同步优先级”(例如紧急的用户交互)和“非同步优先级”(如数据加载的过渡状态等) , 确保用户的高优先级任务可以优先得到处理 。
createRoot 配合 React 18 的新特性(如 useTransition、useDeferredValue、Suspense 等) , 使 React 在渲染过程中支持更细粒度的任务控制:
- useTransition 和 useDeferredValue:这些 API 利用调度器和优先级机制 , 使得非紧急任务可以推迟执行 。
- Suspense 和 SuspenseList:Suspense 组件可以配合 createRoot 实现更好的异步加载体验 , 让 React 在等待数据加载时渲染占位符 , 而非阻塞整个页面 。
React 18 的 createRoot 中引入了更智能的 自动批处理 , 即使在异步事件(如 Promise 回调、setTimeout 等)中触发的多次状态更新 , 也会被批处理为一次渲染 。 批处理减少了不必要的重渲染次数 , 进一步优化了性能 。
5.从ReactDOM.render到createRoot的改进
在 React 17 及以下版本中 , ReactDOM.render 方法会直接执行同步渲染 , 而 createRoot 在内部进行了并发渲染的切换 。 与 ReactDOM.render 的同步渲染模式不同 , createRoot 提供的并发渲染方式可以在渲染过程中暂停、恢复或中止任务 , 从而大幅提升渲染的灵活性 。
6.渲染生命周期管理
createRoot 在调度任务时不仅考虑当前任务的优先级 , 还通过 Fiber 树的状态管理机制确保应用的各个节点更新状态的独立性 。 即每个节点的更新会被追踪 , React 可以在节点级别重新安排渲染计划 , 灵活处理应用生命周期中的更新过程 。
示例:createRoot的使用
在 React 18 中 , 使用 createRoot 来渲染应用的代码如下:
import { createRootfrom 'react-dom/client';import App from './App';const container = document.getElementById('root');const root = createRoot(container); // 创建一个并发根节点root.render(<App />); // 使用并发渲染模式来渲染根组件
总结createRoot 是 React 18 中用于启用并发模式的核心 API , 它结合了 Fiber 架构的可中断任务、调度优先级、批处理更新和时间切片技术 , 从而优化了 React 的渲染性能 , 使得复杂应用在高负载情况下依然可以提供流畅的用户体验 。
推荐阅读
- 中国突然申请7纳米光刻机专利,全球都盯着华为,这背后有啥玄机
- vivo新机突然入网:50Mp潜望镜+90W有线快充,拍照续航双提升
- 固态电池第一龙头,背靠国资委,与华为深度合作,有望强势起飞!
- 预算只有600元?难道真不能买手机,只配买点肉吃?
- 彻底定了,红米K80Pro搭载骁龙8至尊+6500mAh,还有50W无线充电
- 原价随便买,ps5pro发售没有抢购潮
- 现在有哪些新兴技术正在改变着液晶显示屏的产业
- 美团王兴和王慧文有缘,两个人又搞到一起了
- 任天堂官方公布Switch 2两大重点功能!这下不愁没有游戏玩了
- 补贴资金有限!深圳数码3C产品国补今日停止