好的,针对你文档中缺失的这些高频、高阶、且符合 2026 年技术趋势的考点,我为你整理了这份中英文双语背诵清单。
这些题目是区分“初级开发”和“资深/全栈开发”的关键。
(什么是 Fiber 及其如何实现并发渲染?)
(渲染阶段与提交阶段的区别)
(什么是 Hooks 里的“闭包陷阱”以及如何解决?)
useEffect or useCallback) captures a variable from an old render instead of the current one. To solve this, we should always include all necessary variables in the dependency array or use the functional update pattern (e.g., setCount(c => c + 1)).useEffect)捕获了旧渲染周期中的变量而不是当前变量时。解决方法是:确保依赖数组包含所有使用的外部变量,或者使用 “函数式更新” 模式(例如 setCount(c => c + 1))。(useEffect 和 useLayoutEffect 的区别)
useEffect runs asynchronously after the browser has painted the screen, which prevents blocking the UI. useLayoutEffect runs synchronously after DOM mutations but before the browser paints. It is used to measure DOM elements or prevent UI flickering.useEffect 在浏览器完成绘制后异步执行,不会阻塞 UI。useLayoutEffect 在 DOM 变更后但浏览器绘制之前同步执行,通常用于测量 DOM 元素尺寸或防止 UI 闪烁。
(服务端组件与客户端组件:如何选择?)
onClick), browser APIs (e.g., window), or React Hooks (useState, useEffect).window)或 React Hooks(如 useState)时使用客户端组件。(什么是水合以及为什么会发生水合失效?)
Date.now() or Math.random() during rendering.(Server Actions 在 React 19/Next.js 16 中如何工作?)
useActionState hook, they eliminate the need for manual API route creation and handle loading/error states automatically.useActionState Hook,它们消除了手动创建 API 路由的需求,并能自动处理加载和错误状态。
(如何防止使用 Context 时的不必要渲染?)
React.memo. 3. Pass the UI as children to the provider to use composition.React.memo 包裹子组件;3. 将 UI 作为 children 传入 Provider,利用组合模式规避渲染。针对 React 的高级面试,面试官通常不再关注基础 API 的使用,而是倾向于考察底层机制、性能瓶颈、复杂状态管理以及框架设计哲学。
这里我为你整理了一份 React 高级/资深面试题清单,分为四个核心维度:
Fiber 树的遍历: 既然 Fiber 是链表结构,它是如何实现深度优先遍历的?child、sibling 和 return 指针分别起什么作用?
English: React Fiber uses a Linked List structure to perform a Depth-First Search (DFS).
- child: Points to the first child node.
- sibling: Points to the next sibling node.
- return: Points back to the parent node. React goes down to the leaf via
child, then moves to thesibling. If no sibling exists, it goes back to the parent viareturnand looks for the parent's sibling. This non-recursive approach allows React to pause and resume rendering at any time.中文: React Fiber 使用链表结构来实现深度优先遍历 (DFS)。
- child:指向第一个子节点。
- sibling:指向下一个兄弟节点。
- return:指向父节点。 React 通过
child向下遍历到叶子节点,然后通过sibling找到兄弟。如果没有兄弟,则通过return回到父节点并找父节点的兄弟。这种非递归的遍历方式使得 React 可以随时暂停和恢复渲染。
合成事件系统: React 为什么要自己实现一套事件系统?React 17 之后事件委托的挂载点发生了什么变化?为什么?
English: React implements SyntheticBaseEvent for cross-browser compatibility and performance optimization (via event delegation).
- Change: In React 17+, events are attached to the Root DOM Container (e.g.,
#app) instead of thedocument.- Why: This allows multiple React versions to coexist on one page and makes it easier to integrate React into apps managed by other technologies without event bubbling conflicts.
中文: React 实现合成事件是为了跨浏览器兼容性和性能优化(通过事件委托)。
- 变化: 在 React 17 及以后,事件被挂载到 Root 根容器(如
#app)上,而不是document。- 原因: 这允许同一页面运行多个 React 版本,并使 React 更容易集成到其他技术管理的应用中,避免了事件冒泡冲突。
Lanes 模型: React 18 如何通过 Lanes(车道模型)来管理任务优先级?它解决了以前 ExpirationTime 模型的什么痛点?
English: The Lanes model represents different types of updates using 32-bit binary integers (bits).
- Pain Point: The old
ExpirationTimemodel used numbers to represent time, which only allowed for "earlier vs. later" comparison. It couldn't easily handle "interleaving" multiple updates of different types.- Solution: Lanes allow React to group, prioritize, and overlap tasks (e.g., giving user input a "high priority" lane and data fetching a "low priority" lane).
中文: Lanes 模型使用 32 位二进制整数(位图)来表示不同类型的更新。
- 痛点: 旧的
ExpirationTime模型用数字表示时间,只能进行“早晚”比较,难以处理多种不同类型更新的“交替运行”。- 解决方案: Lanes 允许 React 对任务进行分组、优先级排序和重叠处理(例如,给用户输入分配“高优先级”车道,给数据获取分配“低优先级”车道)。
双缓存技术: React 运行时的 current 树和 workInProgress 树是如何交替切换的?
English: React Fiber uses Double Buffering to manage updates.
- The current tree represents what is already on the screen.
- The workInProgress tree is built in memory during the render phase. Once the update is finished, React simply changes the
root.currentpointer to theworkInProgresstree, making it the newcurrenttree. This ensures the user never sees a partial or flickering UI.中文: React Fiber 使用双缓存管理更新。
- current 树代表屏幕上已有的 UI。
- workInProgress 树是在渲染阶段在内存中构建的。 一旦更新完成,React 只需将
root.current指针指向workInProgress树,使其成为新的current树。这确保用户永远不会看到更新一半或闪烁的 UI。
Hooks 的闭包陷阱: 为什么在 useEffect 或 useCallback 中拿到的状态可能是旧值?除了 useRef,还有什么工程化的手段可以规避?
English: A Stale Closure occurs when a Hook captures state from an old render cycle.
- Solution 1: Proper Dependency Array management.
- Solution 2: Functional Updates (e.g.,
setCount(prev => prev + 1)).- Engineering approach: Use the
useEventpattern (oruseRefto store the latest value) to ensure functions always have access to the latest state without triggering re-renders.中文: 闭包陷阱是指 Hook 捕获了旧渲染周期中的状态。
- 解法 1: 严格管理依赖数组。
- 解法 2: 使用函数式更新(如
setCount(prev => prev + 1))。- 工程化手段: 使用
useEvent模式(或通过useRef存储最新值)来确保函数始终能访问最新状态,同时不触发重渲染。
useState 的实现: 如果让你手写一个极简的 Hooks 调度,它是如何保证每次渲染时 Hook 的执行顺序和数据对应的?
English: React relies on a stable call order. Internally, Fiber stores Hooks as a Linked List. During every render, React keeps an index pointer. Each
useXcall fetches the next Hook node in the list. If you call Hooks insideifstatements, the order breaks, leading to React fetching the wrong state for the wrong Hook.中文: React 依赖于稳定的调用顺序。在内部,Fiber 将 Hooks 存储为单向链表。每次渲染时,React 维护一个指针。每个
useX调用都会按顺序获取链表中的下一个 Hook 节点。如果你在if语句中调用 Hook,顺序就会被打乱,导致 React 为错误的 Hook 获取了错误的状态。
批量更新 (Batching): React 18 的 Automatic Batching 相比之前版本有哪些提升?在什么情况下它不会自动合并更新?
English: In React 18, Automatic Batching merges multiple state updates into a single re-render, even inside Promises,
setTimeout, or native event handlers.
- Exception: It won't batch if you use
flushSync, which forces an immediate, synchronous re-render.中文: 在 React 18 中,自动批处理将多个状态更新合并为一次重渲染,即使是在 Promise、
setTimeout或原生事件处理程序中。
- 例外情况: 如果你使用
flushSync,它会强制进行立即的、同步的重渲染,此时不会自动合并。
useLayoutEffect vs useEffect: 它们在浏览器渲染流程中的具体执行时机有什么区别?在什么场景下必须使用前者?
English:
useLayoutEffect: Executes synchronously after DOM mutations but before the browser paints. Use it when you need to measure DOM or change UI to prevent flickering.useEffect: Executes asynchronously after the browser has painted. It is non-blocking and suitable for most side effects like data fetching.中文:
useLayoutEffect:在 DOM 变更后、浏览器绘制之前同步执行。当你需要测量 DOM 或修改 UI 以防止闪烁时使用。useEffect:在浏览器绘制之后异步执行。它是非阻塞的,适用于大多数副作用,如数据获取。
Diff 算法的局限性: 既然 Diff 是 ,为什么在处理跨层级移动节点时,React 会选择直接销毁并重建?
English:
To keep the Diff algorithm at complexity, React assumes that components at different levels are different. Searching the whole tree for a moved node would be . React sacrifices local performance for global speed; it unmounts the old subtree and mounts a new one at the new location.
中文:
为了保持 Diff 算法 的复杂度,React 假设不同层级的组件是不同的。在整棵树中搜索移动的节点复杂度将达到 。React 牺牲了局部性能来换取整体速度:它会直接卸载旧子树并在新位置挂载新子树。
Context 的性能瓶颈: 当 Provider 的 value 发生变化时,所有消费该 Context 的组件都会重新渲染。在不拆分 Provider 的前提下,有哪些方案可以优化?
English:
- Split the component: Move the part that consumes Context into a child and wrap it in
React.memo.- Use composition: Pass the static part of the UI as
children.useMemoinside the component: Wrap the expensive UI return inuseMemo, depending only on the specific field from Context.中文:
- 拆分组件:将消费 Context 的部分提取到子组件并用
React.memo包裹。- 使用组合模式:将 UI 的静态部分作为
children传入。- 组件内
useMemo:将昂贵的 UI 渲染结果用useMemo包裹,仅依赖于 Context 中的特定字段。
Keep-Alive 的实现: React 官方目前没有提供类似 Vue 的 <keep-alive>,如果是你,你会如何设计一个能缓存组件状态和 DOM 的方案?
English: Since React doesn't have a built-in Keep-Alive, we can:
- CSS approach: Use
display: noneto hide the component without unmounting.- Portal approach: Use
createPortalto render the component into a "hidden DOM container" in memory, and then "teleport" it back to the visible tree when needed. This preserves both DOM state and React internal state.中文: 由于 React 没有内置 Keep-Alive,我们可以:
- CSS 方案:使用
display: none隐藏组件而不卸载。- Portal 方案:使用
createPortal将组件渲染到内存中的“隐藏 DOM 容器”,并在需要时将其“传送”回可见树。这可以同时保留 DOM 状态和 React 内部状态。
HOC vs Render Props vs Hooks: 随着 React 的演进,这三种逻辑复用模式分别解决了什么问题,又各自带来了什么副作用?
English:
- HOC: Solved logic reuse but caused "Wrapper Hell" and prop name conflicts.
- Render Props: Solved prop naming issues but caused "Callback Hell" in JSX.
- Hooks: Solved both by allowing flat logic reuse without nesting, making code easier to read and test. Side effect: Introduced the complexity of closures and the rules of hooks.
中文:
- HOC:解决了逻辑复用,但导致了“嵌套地狱”和属性名冲突。
- Render Props:解决了属性命名问题,但导致了 JSX 中的“回调地狱”。
- Hooks:通过扁平化的逻辑复用解决了上述问题,无需嵌套。副作用:引入了闭包的复杂性和 Hooks 调用规则的限制。
Server Components (RSC): 它与传统的 SSR(服务端渲染)有什么本质区别?为什么说它能极大地减少客户端的 Bundle Size?
English: SSR sends HTML to the client for faster initial viewing, but still requires the full JS bundle for hydration. RSC sends a serialized JSON and never sends its code to the client. This means heavy libraries used in RSC stay on the server, resulting in Zero Bundle Size for those components.
中文: SSR 将 HTML 发送给客户端以实现快速首屏,但仍需下载全量 JS 进行水合。RSC 发送的是序列化 JSON,且其代码永远不会发送到客户端。这意味着在 RSC 中使用的大型库都留在服务端,从而实现这些组件的零包体积
Hydration (注水): 什么是“水合失效”?在 Next.js 等框架中,为什么会出现服务端和客户端渲染内容不一致的报错?
English: Hydration is when React "attaches" interactivity to server-rendered HTML. Hydration Mismatch occurs when the client-rendered UI is different from the server-rendered HTML.
- Reason: Usually caused by inconsistent data, like using
Date.now()orwindow(which only exists on client) during the initial render.中文: 水合是 React 将交互性“绑定”到服务端渲染的 HTML 上的过程。水合失效是指客户端渲染的 UI 与服务端返回的 HTML 不一致。
- 原因: 通常由不一致的数据引起,例如在初始渲染时使用了
Date.now()或仅存在于客户端的window对象。
Suspense 的原理: Suspense 是如何通过捕获 Promise 来实现加载状态切换的?它在并发模式下扮演了什么角色?
English: When a component is not ready (loading data), it throws a Promise.
Suspensecatches this promise in its "Error Boundary-like" mechanism, renders thefallbackUI, and waits. When the Promise resolves, React re-tries the render. In Concurrent mode, this allows React to work on multiple UI versions without freezing the main thread.中文: 当组件未就绪(正在加载数据)时,它会抛出(throw)一个 Promise。
Suspense在其类似于错误边界的机制中捕获这个 Promise,渲染fallbackUI 并等待。当 Promise 完成时,React 会重新尝试渲染。在并发模式下,这允许 React 同时处理多个 UI 版本而不阻塞主线程。