豆包react原理
React 底层原理在前端面试中非常常见,以下是一些核心问题及解析,涵盖 React 核心机制、 Fiber 架构、状态管理、虚拟 DOM 等关键领域:
1. React 的 Fiber 架构是什么?解决了什么问题?
- 定义:Fiber 是 React 16 引入的重新实现的协调(Reconciliation)引擎,本质是一种「可中断、可恢复、优先级可控」的工作单元数据结构。
- 解决的问题 :
- 旧架构中,递归协调(Stack Reconciler)会占用主线程导致长时间阻塞(如动画卡顿、用户交互无响应),因为 JavaScript 是单线程,无法中断递归调用栈。
- Fiber 将渲染工作拆分为小单元,每个单元执行完后可暂停、恢复或放弃,通过「时间切片(Time Slicing)」和「优先级调度」,确保高优先级任务(如用户输入)优先执行。
- 核心特点 :
- 可中断:每个 Fiber 节点对应一个组件,工作单元可被暂停。
- 优先级:不同任务(如用户输入 > 动画 > 渲染)有不同优先级(Scheduler 模块管理)。
- 双缓存:当前 Fiber 树(current)和工作 Fiber 树(workInProgress)交替渲染,提升性能。
2. React 的虚拟 DOM(Virtual DOM)是什么?为什么能提升性能?
- 定义 :虚拟 DOM 是 JavaScript 对象(如
{ type: 'div', props: { ... }, children: [...] }),用于描述真实 DOM 的结构,是对真实 DOM 的抽象。 - 性能优化逻辑 :
- 真实 DOM 操作昂贵(重排/重绘成本高),而 JS 对象操作轻量。
- React 通过「Diff 算法」对比新旧虚拟 DOM 树的差异,只更新必要的真实 DOM(最小化 DOM 操作)。
- 批量更新:虚拟 DOM 收集所有变更后一次性同步到真实 DOM,减少多次零散更新的开销。
- 注意:虚拟 DOM 并非一定比直接操作 DOM 快,其优势在于「抽象层带来的开发效率提升」和「跨平台能力」(如 React Native),以及批量更新、Diff 优化等机制的加持。
3. React 的 Diff 算法有什么特点?与 Vue 的 Diff 有何区别?
- React Diff 核心策略 (基于 Fiber 架构):
- 树级对比:只对比同层节点,不同层节点直接销毁重建(不跨层级移动节点,降低复杂度)。
- 组件级对比 :
- 同类型组件:继续对比内部子节点。
- 不同类型组件:直接销毁旧组件,创建新组件。
- 元素级对比 (列表):
- 依赖
key标识节点唯一性,通过key快速定位相同节点,减少移动/销毁操作。 - 若没有
key,默认按索引对比,可能导致大量不必要的重渲染(如列表插入/删除元素时)。
- 依赖
- 与 Vue Diff 的区别 :
- Vue 会尝试跨层级移动节点(React 不跨层级)。
- Vue 对列表 Diff 做了更多优化(如双端对比),React 主要依赖
key优化列表。 - 核心思想一致:最小化 DOM 操作,但实现细节不同。
4. React 的状态更新(setState)是同步还是异步?为什么?
- 结论 :取决于执行环境:
- 异步更新 :在 React 合成事件(如
onClick)、生命周期钩子(如componentDidMount)中,setState是「批量异步更新」,多次调用会合并,避免频繁渲染。 - 同步更新 :在原生事件(如
addEventListener)、setTimeout/Promise回调等非 React 管控的环境中,setState是同步的,会立即触发重渲染。
- 异步更新 :在 React 合成事件(如
- 原理:React 通过「事务(Transaction)」或「批处理机制(batchingUpdates)」管控更新,在合成事件/生命周期中,会将更新放入队列,结束后统一执行;非管控环境中无法触发批处理,因此同步执行。
- 注意 :React 18 中引入「自动批处理(Automatic Batching)」,无论是否在 React 管控环境,默认批量更新(可通过
flushSync强制同步)。
5. React 的生命周期中,哪些方法会在 Fiber 架构下被中断或重启?
- Fiber 架构下,「协调阶段(Reconciliation)」的生命周期可能被中断或重启,因为协调阶段的工作可被高优先级任务抢占:
- 可能被中断的方法:
componentWillMount、componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate(这些方法可能执行多次,因此 React 建议使用getDerivedStateFromProps等替代)。
- 可能被中断的方法:
- 「提交阶段(Commit)」的生命周期不会被中断,因为此时已进入真实 DOM 更新阶段,必须一次性完成:
- 不会中断的方法:
componentDidMount、componentDidUpdate、componentWillUnmount。
- 不会中断的方法:
6. React Hooks 的底层原理是什么?为什么不能在条件语句中使用 Hooks?
- 底层原理 :
- Hooks 依赖 React 内部维护的「链表」存储状态,每个组件对应一个
fiber节点,fiber.memoizedState指向该组件的 Hooks 链表头。 - 调用
useState/useEffect等 Hooks 时,会按顺序创建/读取链表节点(如useState的状态存在链表节点中)。
- Hooks 依赖 React 内部维护的「链表」存储状态,每个组件对应一个
- 不能在条件语句中使用的原因 :
- Hooks 依赖「调用顺序」与链表节点一一对应。若在条件语句中使用(如
if (flag) { useState() }),会导致后续 Hooks 调用顺序与链表节点错位,引发状态混乱或报错。 - React 通过 ESLint 规则
eslint-plugin-react-hooks强制检查 Hooks 调用顺序。
- Hooks 依赖「调用顺序」与链表节点一一对应。若在条件语句中使用(如
7. React 的协调(Reconciliation)与提交(Commit)阶段有什么区别?
- 协调阶段(Reconciliation) :
- 作用:对比新旧虚拟 DOM,找出差异(Diff 过程),确定需要更新的节点。
- 特点:可中断、可恢复(Fiber 架构支持),不操作真实 DOM,只标记变更(如「删除」「更新」「移动」)。
- 提交阶段(Commit) :
- 作用:将协调阶段标记的变更应用到真实 DOM 上。
- 特点:不可中断,分为三个子阶段:
before mutation:执行getSnapshotBeforeUpdate。mutation:执行 DOM 操作(增删改)。layout:执行componentDidMount/componentDidUpdate,更新ref等。
8. React 如何实现批量更新(Batching)?
-
原理:React 会将多个状态更新合并为一次渲染,减少重绘次数。
-
实现方式 :
- 维护一个更新队列(
updateQueue),setState调用时不会立即更新状态,而是将更新任务加入队列。 - 在合适的时机(如事件回调结束、生命周期结束),通过
scheduleUpdateOnFiber触发批量执行队列中的更新,计算最终状态并渲染。
- 维护一个更新队列(
-
React 18 变化 :引入
createRoot,默认对所有更新(包括setTimeout、Promise 等)进行自动批处理,若需强制同步更新,可使用flushSync:jsximport { flushSync } from 'react'; flushSync(() => { setCount(c => c + 1); });
9. React 的 Context 机制底层是如何实现的?有什么性能问题?
- 实现原理 :
- Context 通过「生产者-消费者」模式传递数据,
Context.Provider会将数据存储在当前 Fiber 节点的context属性中。 - 当
Provider的value变化时,会触发其所有子孙节点中使用useContext或Consumer的组件重新渲染(无论是否使用了memo)。
- Context 通过「生产者-消费者」模式传递数据,
- 性能问题 :
- 若
Provider的value频繁变化,会导致所有消费组件不必要的重渲染(即使组件未使用变化的部分数据)。 - 优化方式:将
value拆分为多个 Context,或使用useMemo缓存value(避免引用变化)。
- 若
10. React 18 有哪些重要更新?
- 并发渲染(Concurrent Rendering):支持渲染过程中断、恢复,提升用户交互体验。
- 自动批处理(Automatic Batching):统一不同环境下的批量更新行为。
- Transitions API:区分紧急更新(如输入)和非紧急更新(如列表筛选),避免卡顿。
- 服务器组件(Server Components):允许组件在服务器渲染,减少客户端 JS 体积。
- 新的根 API:
createRoot替代ReactDOM.render,支持并发特性。
千问React 底层原理
React 底层相关的面试题通常聚焦于其核心机制、架构原理和性能优化策略。以下是常见且高频的 React 底层面试题,附带简明解释,适合中高级前端工程师准备:
1. React 的 Fiber 架构是什么?为什么要引入 Fiber?
答:
Fiber 是 React 16 引入的新协调(reconciliation)引擎,将原本递归的 diff 过程改为可中断、可恢复的增量式更新。
目的:
解决大型应用中同步更新导致主线程阻塞、页面卡顿的问题;
支持任务优先级调度(如用户输入 > 数据更新);
为并发模式(Concurrent Mode)打下基础。
2. React 的渲染流程(从 setState 到 DOM 更新)是怎样的?
答:(以类组件为例)
- 调用 setState() 触发更新;
- React 将更新放入一个更新队列(Update Queue);
- 启动 render 阶段(可中断):
从根节点开始构建新的 Fiber 树(work-in-progress tree);
执行 diff 算法(双缓存机制); - 进入 commit 阶段(不可中断):
应用副作用(DOM 操作、useEffect 等);
更新真实 DOM; - 触发生命周期或 hooks 回调(如 componentDidMount / useLayoutEffect / useEffect)。
3. React 的 diff 算法原理是什么?
答:
React 采用启发式 O(n) diff 算法,基于三个假设:
- 不同类型的元素产生不同的树 → 直接销毁重建;
- 通过 key 属性稳定识别同层级子元素 → 避免不必要的移动/重建;
- 组件状态在跨渲染时保持稳定。
具体策略:
Tree Diff:只对同层级节点比较,不跨层级;
Component Diff:类型不同则整棵子树重建;
Element Diff:通过 key 对比子节点列表,复用已有实例。
4. 什么是双缓存 Fiber 树(Current / WorkInProgress)?
答:
React 维护两棵 Fiber 树:
current:当前正在屏幕显示的真实 DOM 对应的 Fiber 树;
workInProgress:正在内存中构建的下一帧 Fiber 树。
渲染完成后,两者交换(fiber.alternate 指针互换),实现无闪烁更新,并支持错误回退。
5. React 如何实现批量更新(Batching)?
答:
在 React 18 之前,只有 React 事件处理器中的 setState 会被自动批处理;
React 18 默认开启自动批处理(Automatic Batching),即使在 Promise、setTimeout、原生事件中也会合并多个 setState;
原理:通过维护一个 isBatchingUpdates 标志位,在事件循环结束前收集所有更新,统一触发一次 re-render。
可通过 flushSync 强制退出批处理。
6. Hooks 的底层实现原理?为什么不能在条件语句中使用?
答:
Hooks 本质是通过 链表 存储在 Fiber 节点的 memoizedState 字段中;
每次渲染时,按固定顺序遍历链表,依次执行每个 Hook;
如果在条件/循环中使用,会导致 Hook 顺序变化,造成状态错乱(如 useState 返回错误的值)。
7. React 事件系统与原生 DOM 事件有何不同?
答:
React 使用合成事件(SyntheticEvent),是对原生事件的跨浏览器封装;
事件委托到 document(React 16)或 root 容器(React 17+),减少内存开销;
支持自动池化(event pooling,已废弃)、阻止冒泡统一 API;
合成事件对象在异步回调中可能失效(需 e.persist() 或解构保存,React 17+ 已移除限制)。
8. React 的调度机制(Scheduler)是如何工作的?
答:
Scheduler 基于 MessageChannel + requestIdleCallback polyfill 实现;
将任务按优先级(如 user-blocking、normal、low)分配时间片;
利用 时间切片(Time Slicing) 在每一帧空闲时间执行部分 work,避免阻塞主线程;
高优先级任务可打断低优先级任务(如输入响应打断数据加载)。
9. React.memo / useMemo / useCallback 的作用和区别?
React.memo:高阶组件,浅比较 props,避免函数组件不必要重渲染;
useMemo:缓存计算结果,依赖不变则返回缓存值;
useCallback:缓存函数引用,等价于 useMemo(() => fn, deps);
注意:它们都不能"提升性能",滥用反而增加开销,仅用于优化已知性能瓶颈。
10. React 18 的并发特性(Concurrent Features)有哪些?
自动批处理(Automatic Batching)
Transition(startTransition):标记非紧急更新,允许被高优任务打断;
Suspense for Data Fetching(实验性):配合 use)支持数据加载时的 loading 状态;
Selective Hydration:服务端渲染时优先 hydrate 可交互区域。
如果你需要更深入某个点(比如 Fiber 节点结构、调度优先级源码分析、diff 算法伪代码等),可以继续问我!
deepseek React 底层原理
1. Virtual DOM 和 Diff 算法
题目:React 的 Virtual DOM 是什么?Diff 算法如何工作?
参考答案:
Virtual DOM 是 React 的核心概念之一,它是一个轻量级的 JavaScript 对象,是对真实 DOM 的抽象。当组件状态变化时,React 会先在 Virtual DOM 上进行计算,然后通过 Diff 算法找出变化的部分,最后批量更新到真实 DOM。
Diff 算法的工作流程:
- 树对比:React 对两棵树进行层级比较,只对同一层级的节点进行比较
- 组件对比 :
- 如果是同类型组件,继续递归比较
- 如果是不同类型组件,直接替换整个组件
- 元素对比 :
- 使用 key 属性来识别稳定元素
- 没有 key 时按顺序比较,可能导致性能问题
优化策略:
- 同一层级的节点移动操作会被优化
- 使用 key 避免不必要的重新渲染
2. Fiber 架构
题目:React Fiber 是什么?解决了什么问题?
参考答案:
React Fiber 是 React 16 引入的新的协调引擎,是对 React 核心算法的重写。
解决的问题:
- 同步渲染阻塞:旧版本 React 的渲染过程是同步的,可能阻塞主线程
- 任务优先级:无法区分高优先级和低优先级任务
- 增量渲染:支持将渲染工作分割成多个小任务
Fiber 的特点:
- 可中断:渲染过程可以被中断,让出主线程给更高优先级的任务
- 增量渲染:将渲染工作分成多个小任务
- 错误边界:更好的错误处理机制
- 优先级调度:基于任务优先级进行调度
3. 生命周期和 Hooks
题目:React Hooks 的实现原理是什么?
参考答案:
Hooks 的实现基于以下几个关键概念:
- 链表结构:Hooks 在组件中是以链表的形式存储的
- 执行顺序:Hooks 的调用顺序在每次渲染时必须保持一致
- 状态存储:每个 Hook 的状态都存储在对应的节点中
javascript
// 简化的 Hook 实现原理
let currentHook = null;
let workInProgressHook = null;
function useState(initialState) {
const hook = {
state: initialState,
queue: [],
next: null
};
// 将 hook 添加到链表
if (!workInProgressHook) {
workInProgressHook = hook;
} else {
workInProgressHook.next = hook;
workInProgressHook = hook;
}
return [hook.state, (action) => {
hook.queue.push(action);
// 触发重新渲染
scheduleUpdate();
}];
}
4. 事件系统
题目:React 的事件系统是如何工作的?
参考答案:
React 实现了自己的合成事件系统(SyntheticEvent),具有以下特点:
- 事件委托:React 将所有事件委托到 document 上(React 17 后改为 root 节点)
- 跨浏览器兼容:提供统一的事件接口
- 性能优化:通过事件池复用事件对象
- 自动清理:组件卸载时自动清理事件处理函数
工作流程:
- 事件绑定到 root 节点
- 事件触发时创建合成事件
- 通过组件树冒泡
- 执行对应的事件处理函数
- 事件对象被回收或销毁
5. 调度机制
题目:React 的调度机制是如何工作的?
参考答案:
React 使用基于优先级的调度系统:
-
任务分类:
- 同步任务(Sync)
- 批量任务(Batched)
- 并发任务(Concurrent)
-
时间切片:将工作分成 5ms 的小任务
-
优先级调度:使用 Lane 模型管理任务优先级
-
可中断渲染:在浏览器空闲时执行任务
javascript
// 简化的调度原理
function workLoop(deadline) {
let shouldYield = false;
while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
shouldYield = deadline.timeRemaining() < 1;
}
if (!shouldYield) {
requestIdleCallback(workLoop);
}
}
requestIdleCallback(workLoop);
6. 性能优化相关
题目:React.memo、useMemo、useCallback 的区别和实现原理?
参考答案:
React.memo:
- 用于函数组件,类似 PureComponent
- 对 props 进行浅比较,避免不必要的重新渲染
useMemo:
- 缓存计算结果,只有在依赖项变化时重新计算
- 适用于昂贵的计算操作
useCallback:
- 缓存函数引用,避免子组件不必要的重新渲染
- 本质上是 useMemo 的语法糖
实现原理:
javascript
function useMemo(factory, deps) {
const hook = getCurrentHook();
if (hook.memoizedState && areEqual(hook.deps, deps)) {
return hook.memoizedState;
}
const newValue = factory();
hook.memoizedState = newValue;
hook.deps = deps;
return newValue;
}
7. Context 原理
题目:React Context 的实现原理是什么?
参考答案:
Context 的实现基于 Provider-Consumer 模式:
- Provider:提供数据,当值变化时通知所有消费者
- Consumer:消费数据,订阅 Context 变化
- 发布订阅模式:使用观察者模式管理订阅
javascript
// 简化的 Context 实现
function createContext(defaultValue) {
const context = {
_currentValue: defaultValue,
Provider: function({ value, children }) {
context._currentValue = value;
return children;
},
Consumer: function({ children }) {
return children(context._currentValue);
}
};
return context;
}
8. 错误边界
题目:React 错误边界的实现原理是什么?
参考答案:
错误边界使用 React 的生命周期方法和类组件实现:
- componentDidCatch:捕获子组件树的 JavaScript 错误
- getDerivedStateFromError:渲染备用 UI
- try-catch 机制:在渲染过程中包装组件树
实现限制:
- 只能捕获子组件的错误
- 不能捕获事件处理、异步代码、服务端渲染的错误
- 只能使用类组件实现
9. 并发特性
题目:React 18 的并发特性是如何实现的?
参考答案:
并发特性基于以下技术:
- 并发渲染:渲染过程可中断,支持多个版本 UI 同时存在
- 自动批处理:将多个状态更新合并为单个重新渲染
- Transition:区分紧急和非紧急更新
- Suspense:更好的异步数据加载体验
javascript
// 使用 startTransition 标记非紧急更新
function handleClick() {
startTransition(() => {
setNonUrgentState(newValue);
});
}
10. 渲染流程
题目:描述 React 组件的完整渲染流程
参考答案:
渲染阶段(Render Phase):
- 创建 Virtual DOM 树
- 执行 Diff 算法比较前后状态
- 收集需要更新的变更
提交阶段(Commit Phase):
- 同步执行 DOM 更新
- 调用生命周期方法(componentDidMount/Update)
- 执行 useEffect 的清理和设置函数
关键特点:
- 渲染阶段可中断,提交阶段不可中断
- 使用双缓存技术避免 UI 不一致
- 批量更新优化性能
这些底层原理的理解有助于在面试中展示对 React 的深入认识,同时也能在实际开发中更好地进行性能优化和问题排查。
文心一言 react 底层
在 React 底层相关的面试中,可能会涉及虚拟 DOM、组件生命周期、事件机制、状态管理、性能优化等核心原理和技术细节,以下是一些典型的面试问题及解析:
虚拟 DOM(Virtual DOM)
问题:React 为什么要使用虚拟 DOM?它是如何提高性能的?
解析:
原因:直接操作真实 DOM 成本较高,频繁的 DOM 操作会导致页面性能下降。虚拟 DOM 是一个轻量级的 JavaScript 对象,它模拟了真实 DOM 的结构。React 通过比较新旧虚拟 DOM 的差异,以最小的代价更新真实 DOM,从而提高性能。
性能提升:虚拟 DOM 通过 diff 算法比较新旧虚拟 DOM 的差异,只更新变化的部分,而不是重新渲染整个页面。这减少了不必要的 DOM 操作,提高了页面渲染效率。
组件生命周期
问题:请描述 React 组件的生命周期方法及其作用。
解析:
挂载阶段:
constructor():组件初始化时调用,用于设置初始状态和绑定方法。
static getDerivedStateFromProps(props, state):在组件挂载前和更新前调用,根据新的 props 更新内部状态(较少使用)。
render():返回组件的虚拟 DOM 结构。
componentDidMount():组件挂载完成后调用,常用于发起网络请求或操作 DOM。
更新阶段:
static getDerivedStateFromProps(props, state)(同上)。
shouldComponentUpdate(nextProps, nextState):决定组件是否重新渲染,可用于性能优化。
render()(同上)。
getSnapshotBeforeUpdate(prevProps, prevState):在 DOM 更新前捕获一些信息(如滚动位置),较少使用。
componentDidUpdate(prevProps, prevState, snapshot):组件更新完成后调用,可用于执行依赖于 DOM 的操作。
卸载阶段:
componentWillUnmount():组件卸载前调用,常用于清理定时器、取消网络请求等。
事件机制
问题:React 中的事件处理机制与原生 DOM 事件有何不同?
解析:
合成事件:React 使用合成事件(SyntheticEvent)来包装原生浏览器事件,以提供跨浏览器兼容性。合成事件与原生事件具有相同的接口,但内部实现不同。
事件委托:React 采用事件委托机制,将所有事件都绑定到文档的根节点上,通过事件冒泡来触发相应组件的事件处理函数。这减少了内存消耗,提高了性能。
自动绑定:在类组件中,React 会自动绑定事件处理函数的 this 上下文为组件实例,避免了手动绑定的繁琐。
状态管理
问题:React 中如何管理组件的状态?有哪些状态管理库?
解析:
组件内部状态:使用 useState(函数组件)或 this.state(类组件)来管理组件内部状态。
上下文(Context):使用 React.createContext 创建上下文,通过 useContext(函数组件)或 Context.Consumer(类组件)来共享状态。
状态管理库:如 Redux、MobX 等,用于管理复杂应用的全局状态。这些库提供了更强大的状态管理功能,如状态持久化、中间件等。
性能优化
问题:React 中有哪些性能优化技巧?
解析:
避免不必要的渲染:使用 React.memo(函数组件)或 PureComponent(类组件)来避免不必要的重新渲染。这些组件会在 props 未变化时跳过渲染。
使用 shouldComponentUpdate:在类组件中,可以通过实现 shouldComponentUpdate 方法来手动控制组件的更新逻辑,避免不必要的渲染。
代码分割和懒加载:使用 React.lazy 和 Suspense 来实现代码分割和懒加载,减少初始加载时间。
使用虚拟列表:对于长列表数据,使用虚拟列表技术来只渲染可见部分的数据,提高页面性能。
以下是一些常见的 React 底层面试题 及其 原理性详解 ,内容涵盖 Fiber 架构、Diff 算法、Hooks 原理、合成事件、渲染流程 等核心模块,适用于深入理解 React 底层机制的中高级前端开发者。
KIMI react 原理
一、React Fiber 架构原理
❓面试题:React 为什么要引入 Fiber 架构?它的核心原理是什么?
✅原理详解:
React 15 使用的是 Stack Reconciler ,其更新过程是同步递归的,一旦开始就无法中断,导致大量计算阻塞主线程,造成页面卡顿。
Fiber 架构的设计动机:
- 实现可中断的异步渲染
- 支持任务分片 和优先级调度
- 提高用户体验,避免掉帧
Fiber 的核心原理:
- 每个组件对应一个 Fiber 节点 ,构成链表树结构
- 使用 双缓存机制:维护两棵树(current 和 workInProgress)
- 渲染过程分为两个阶段:
- Render 阶段(可中断):构建 Fiber 树,标记副作用
- Commit 阶段(不可中断):执行 DOM 更新、生命周期、Hook 等
Fiber 节点结构:
js
class FiberNode {
tag: WorkTag, // 组件类型
return: FiberNode, // 父节点
child: FiberNode, // 第一个子节点
sibling: FiberNode, // 兄弟节点
alternate: FiberNode, // 双缓冲指针
memoizedState: any, // 状态(如 Hooks)
effectTag: SideEffectTag, // 副作用标记
}
调度机制:
- 使用
requestIdleCallback模拟时间分片 - 高优先级任务(如用户输入)可打断低优先级任务(如数据同步)
引用:Fiber 架构通过链表结构和时间分片机制,实现了可中断的渲染流程,有效解决了同步渲染导致的卡顿问题 。
二、Diff 算法原理
❓面试题:React 的 Diff 算法是如何工作的?它有哪些优化策略?
✅原理详解:
React 的 Diff 算法是**协调器(Reconciler)**的核心部分,用于比较新旧虚拟 DOM 树,最小化 DOM 操作。
传统 Diff 算法复杂度为 O(n³) ,React 通过以下策略将其优化为 O(n):
✅三大优化策略:
- 只进行同级比较(不跨层级)
- 不同类型元素直接销毁重建
- 使用 key 标识子节点,优化列表渲染
✅Diff 过程分类:
- 单节点 Diff:比较 key 和 type,判断是否可复用
- 多节点 Diff :
- 使用 key 建立旧节点映射表
- 遍历新节点,查找可复用节点
- 判断是否需要移动、插入或删除
- 使用
lastPlacedIndex变量优化节点移动逻辑
引用:React 的 Diff 算法通过 key 和类型判断节点是否可复用,极大提升了渲染效率 。
三、Hooks 原理
❓面试题:React 中 Hooks 是如何在函数组件中实现状态管理的?
✅原理详解:
Hooks 是 React 16.8 引入的特性,使函数组件具备状态、生命周期等能力。
✅底层实现机制:
-
Hooks 使用链表结构存储状态
-
每次渲染时,按顺序调用 Hooks,形成稳定的调用链
-
每个 Hook 对象包含:
js{ memoizedState: any, // 当前状态 baseState: any, // 初始状态 queue: UpdateQueue, // 更新队列 next: Hook | null, // 下一个 Hook }
✅useState 原理:
- 首次渲染:创建 Hook 对象并初始化状态
- 更新阶段:从更新队列中计算新状态
- 调用
setState会创建更新对象并调度重新渲染
✅useEffect 原理:
- 在渲染完成后比较依赖项
- 若依赖变化,则将副作用函数加入执行队列
- 在 commit 阶段统一执行
引用:Hooks 通过链表结构和状态队列,实现了函数组件的状态管理和副作用处理 。
四、合成事件系统原理
❓面试题:React 的合成事件系统是什么?它有哪些优势?
✅原理详解:
React 实现了跨浏览器的合成事件系统(SyntheticEvent),统一了事件处理接口。
✅核心机制:
- 所有事件绑定在 document 上,使用事件委托
- 事件处理函数被封装为合成事件对象
- 事件触发后,React 会根据事件类型和目标组件,分发到对应的事件处理函数
✅优势:
- 跨浏览器兼容
- 减少内存消耗(事件委托)
- 支持事件池机制(React 17 已废弃)
- 与 Fiber 架构协同,支持优先级调度
引用:React 合成事件系统通过统一封装和事件委托,提高了性能和兼容性 。
五、渲染流程与更新机制
❓面试题:React 组件从挂载到渲染的流程是怎样的?setState 后发生了什么?
✅原理详解:
✅初次渲染流程:
- JSX 被编译为
React.createElement调用 - 创建 Fiber 树(beginWork)
- 构建 DOM 树(commit阶段)
- 渲染到页面
✅更新流程:
setState创建更新对象,加入更新队列- 调度器(Scheduler)安排更新任务
- 进入 Render 阶段:构建新的 workInProgress 树
- 进入 Commit 阶段:应用 DOM 更新、执行副作用
✅批处理机制:
- React 18 默认启用自动批处理
- 多个
setState会被合并为一次更新 - 使用
startTransition可标记非紧急更新,避免阻塞用户交互
引用:React 的渲染流程分为 Render 和 Commit 两个阶段,支持任务中断和优先级调度 。
六、React 18 并发特性(加分项)
❓面试题:React 18 的并发渲染有哪些新特性?startTransition 是如何工作的?
✅原理详解:
- 自动批处理:多个 setState 自动合并
- startTransition:标记非紧急更新,避免阻塞高优先级任务
- useTransition:返回 pending 状态,支持加载指示
- Suspense 改进:支持服务端流式渲染
引用:React 18 通过 Lane 模型和 Transition 机制,实现了更细粒度的更新控制 。
✅总结:React 底层核心模块一览
| 模块 | 作用 | 关键技术点 |
|---|---|---|
| Fiber 架构 | 实现可中断渲染、优先级调度 | 链表树、双缓存、时间切片 |
| Diff 算法 | 最小化 DOM 操作 | 同级比较、key 优化、节点复用 |
| Hooks | 函数组件状态管理 | 链表结构、状态队列、顺序调用 |
| 合成事件 | 统一事件处理机制 | 事件委托、合成事件对象 |
| 渲染流程 | 管理组件从挂载到更新的全过程 | Render 阶段、Commit 阶段、批处理机制 |
| 并发特性 | 支持非阻塞更新、提升用户体验 | startTransition、Lane 模型、自动批处理 |
如需针对某一模块(如 Hooks 实现、Lane 模型、Scheduler 源码)深入展开,请告诉我,我可以继续细化。