React 原理

Next.js 原理

react原理

Question 1 React 中 state 更新之后,组件为什么不会立刻同步更新?


你需要至少提到 3 个核心点:

  1. React 不会立即更新 state,而是“收集更新”
  2. 批处理(batching
  3. 调度 / 异步更新(不是同步 setState)

标准面试回答(中文)

React 中 state 更新之后不会立刻同步更新,主要是因为 React 采用了异步更新和批处理机制(batching)来优化性能

当我们调用 setStateuseState 的更新函数时,React 并不会马上去重新渲染组件,而是会:

  1. 先把这次更新放到一个更新队列(update queue)中
  2. 在同一个事件循环中收集多个更新
  3. 最后统一进行一次重新渲染

这样做的好处是:

👉 避免多次重复渲染,提高性能

另外,在 React 18 之后,引入了更强的 调度机制(scheduler)和并发特性(concurrent features),React 可以根据任务优先级决定什么时候更新,而不是立即执行。

 

Standard Answer (English)

In React, state updates are not applied immediately because React uses asynchronous updates and batching for performance optimization.

When you call setState or a state updater function, React does not re-render the component right away. Instead, it:

  1. Queues the update in an update queue
  2. Collects multiple updates within the same event loop
  3. Processes them together in a single render

This helps:

👉 Avoid unnecessary multiple re-renders and improves performance

Starting from React 18, React also introduced a more advanced scheduler and concurrent features, allowing it to prioritize updates instead of executing them immediately.

 

Question 2 React 的 batching(批处理)在 React 18 前后有什么区别?

 

👉 提示一下方向:


标准面试回答(中文)

在 React 18 之前,批处理(batching)只在 React 的事件处理函数中生效,比如点击事件、onChange 等。

也就是说:

例如在 React 17 中:

👉 会触发 两次渲染

 

而在 React 18 中,引入了 自动批处理(automatic batching)

👉 无论是在事件、setTimeout、Promise 还是原生事件中,都会自动批处理

所以上面的代码在 React 18 中:

👉 只会触发 一次渲染


Standard Answer (English)

Before React 18, batching only worked inside React event handlers, such as onClick or onChange.

For example in React 17:

👉 This would cause two re-renders

 

In React 18, React introduced automatic batching:

👉 Updates are batched in all environments, including:

So the same code now results in:

👉 only one re-render


一句话总结(方便记忆)

👉 中文:

React 17 只在事件中批处理,React 18 实现了全局自动批处理。

👉 English:

React 17 batches only in event handlers, while React 18 enables automatic batching everywhere.

 

 

Question 3 (开始进入原理 update queue)

React 是如何知道哪些 state 需要更新的?(update queue 是怎么工作的)


标准面试回答(中文)

React 是通过 Fiber 节点上的 update queue(更新队列) 来管理 state 更新的。

当我们调用 setStateuseState 时,并不是直接修改 state,而是:

1️⃣ 创建一个 update 对象

这个对象会记录:

 

2️⃣ 放入 update queue(链表结构)

每个组件对应一个 Fiber,每个 Fiber 上都有一个:

👉 update queue(本质是一个链表)

多个 setState 会变成这样:

 

3️⃣ 渲染阶段(render phase)统一处理

React 在下一次 render 时,会:

👉 遍历这个链表,把所有 update 依次计算一遍,得到最终 state

例如:

React 会:

👉 最终只渲染一次,state = 2

 

4️⃣ 为什么这样设计?

👉 合并多次更新,避免重复渲染,提高性能

同时配合 React 18:

👉 可以根据“优先级”决定哪些 update 先执行(调度机制)


Standard Answer (English)

React manages state updates using an update queue stored on each Fiber node.

When you call setState or a state updater:

1️⃣ Create an update object

It contains:

 

2️⃣ Push into the update queue (linked list)

Each Fiber has an update queue, which is essentially a linked list:

 

3️⃣ Process during render phase

During rendering, React:

👉 Iterates through the queue and calculates the final state

Example:

👉 Final state = 2, only one render

 

4️⃣ Why this design?

👉 To merge multiple updates and avoid unnecessary re-renders

In React 18, it also allows:

👉 priority-based scheduling


一句话总结(方便记忆)

👉 中文:

React 把 state 更新放在 Fiber 的 update queue(链表)中,在 render 阶段统一计算最终 state。

👉 English:

React stores updates in a Fiber’s update queue and processes them during render to compute the final state.

Question 4(非常高频 + 容易挂 为什么useState直接修改不会触发更新)

为什么 useState 直接修改 state 不会触发更新?

比如:

👉 为什么页面不会更新?


标准面试回答(中文)

直接修改 state(比如 state.count = 1)不会触发更新,是因为:

👉 React 并不会监听对象内部的变化,而是通过“引用变化(reference change)”来判断是否需要更新。


核心原因拆解

1️⃣ React 不做“深度监听”

React 不像一些框架(比如 Vue)会做数据劫持(proxy / defineProperty)。

👉 React 是:

不关心对象里面变了什么,只关心“这个对象是不是变了”

 

2️⃣ useState 的更新机制

当你调用:

React 会做一件事:

👉 对比新旧 state 的引用(浅比较)

如果:

👉 React 认为:没变 → 不更新

 

3️⃣ 直接修改的问题

这个操作:

👉 所以不会触发重新渲染

 

4️⃣ 正确写法

👉 这里创建了一个新对象(新引用)

React 检测到:

👉 触发更新


Standard Answer (English)

Directly mutating state (e.g. state.count = 1) does not trigger a re-render because:

👉 React does not track deep changes — it relies on reference equality to detect updates.


Breakdown

1️⃣ No deep observation

React does NOT observe object internals (no proxy like Vue).

👉 It only checks:

Did the reference change?

 

2️⃣ useState comparison

When calling:

React compares:

 

3️⃣ Problem with mutation

👉 No re-render

 

4️⃣ Correct way

👉 New object → new reference → triggers render


一句话总结(方便记忆)

👉 中文:

React 通过引用是否变化来判断 state 是否更新,直接修改不会改变引用,所以不会触发渲染。

👉 English:

React relies on reference changes, not mutations, to detect state updates.

 

Question 5(Hooks 原理关键题)

useState 为什么可以在函数组件中“记住状态”?

👉 换句话说:

函数每次执行都会重新运行,那 state 是怎么“保存下来”的?


标准面试回答(中文)

useState 能在函数组件中“记住状态”,本质原因是:

👉 React 在 Fiber 上维护了一条 hooks 链表,每次渲染按顺序读取这些 hooks。


核心原理拆解

1️⃣ 不是靠函数本身保存状态

函数组件每次执行:

👉 实际上是重新执行一遍函数

所以:

❌ 不是函数记住了 state ❌ 也不只是闭包(很多人会说错)

 

2️⃣ 状态存在哪里?

👉 存在 Fiber 节点上

每个组件都有一个 Fiber:

👉 这是一条 链表(linked list)

 

3️⃣ useState 做了什么?

当你写:

React 内部会:

  1. 找到当前组件对应的 Fiber
  2. 在 hooks 链表中找到当前这个 hook(靠顺序!)
  3. 返回对应的 state

 

4️⃣ 为什么 hooks 不能写在 if 里?

👉 会破坏“顺序”

React 是这样取的:

如果顺序变了:

👉 React 就会读错 state(错位)

 

5️⃣ setState 做了什么?

👉 本质是:


Standard Answer (English)

useState works because:

👉 React stores hooks in a linked list on the Fiber node and retrieves them by order during each render.


Breakdown

1️⃣ Not stored in the function

Function components re-run every render:

👉 The function does NOT store state

 

2️⃣ Where is state stored?

👉 On the Fiber node

 

3️⃣ How useState works

When calling:

React:

  1. Finds current Fiber
  2. Locates the hook by order
  3. Returns stored state

 

4️⃣ Why hooks must not be conditional

👉 Breaks order → wrong state mapping

 

5️⃣ What setState does

👉 It:


一句话总结(方便记忆)

👉 中文:

useState 的状态不是存在函数里,而是存在 Fiber 的 hooks 链表中,React 通过调用顺序来读取。

👉 English:

useState stores state in a Fiber-linked list and relies on call order to retrieve it.

 

Question 6(核心基础 · 必问 Fiber)

什么是 Fiber?React 为什么要引入 Fiber?

👉 你可以先试着回答哪怕一句,比如:


可以从这几个角度想:

  1. React 以前有什么问题?
  2. 为什么需要“可中断”?
  3. Fiber 和“链表 / 树”有没有关系?

标准面试回答(中文)

Fiber 是 React 16 引入的一种新的架构(reconciliation architecture),本质上是一种数据结构(链表形式的树),用于描述组件的更新过程。

👉 引入 Fiber 的核心目的:

让 React 的渲染过程变成“可中断、可恢复、可优先级调度”的


Standard Answer (English)

Fiber is a reconciliation architecture introduced in React 16, and it is essentially a data structure (a tree implemented with linked lists) used to manage updates.

👉 The main goal of Fiber is:

To make rendering interruptible, resumable, and priority-based


详细解析:

为什么需要 Fiber?(这是面试重点)

❌ 在 Fiber 之前(React 15)

React 使用的是:

👉 递归调用(stack reconciliation)

问题是:


✅ Fiber 做了什么?

👉 把“递归”改成“可拆分任务”

也就是说:

React 可以:


🧩 Fiber 的本质结构

每个组件对应一个 Fiber 节点,结构类似:

👉 这其实是一个:

用链表实现的树结构(方便遍历 & 中断)


⚙️ Fiber 带来的能力(必须记住3个)

1️⃣ 可中断(interruptible)

👉 渲染过程中可以暂停

 

2️⃣ 可恢复(resumable)

👉 下次从中断的地方继续

 

3️⃣ 优先级调度(scheduler)

👉 高优先级任务(用户输入)优先执行


一句话总结(方便记忆)

👉 中文:

Fiber 是 React 的一种新架构,本质是链表结构的组件树,用来实现可中断和可调度的渲染。

👉 English:

Fiber is a React architecture that represents components as linked nodes, enabling interruptible and prioritized rendering.

 

Question 7 (render阶段和commit阶段)

React 为什么要分 render 阶段和 commit 阶段?


标准面试回答(中文)

React 把更新过程分成两个阶段:

 

1️⃣ Render 阶段(也叫 Reconciliation 阶段)

👉 做什么:计算“要不要更新”

在这个阶段,React 会:

⚠️ 关键点:

❗ 这个阶段 不操作真实 DOM

👉 所以它是:

 

一句话理解 Render 阶段:

👉 “先算清楚要改哪里,但先不动 DOM”

 

2️⃣Commit 阶段

👉 做什么:真正“把变化应用到 DOM”

在这个阶段,React 会:

⚠️ 关键点:

❗ 这个阶段必须是同步的,不能中断

原因很简单:

👉 DOM 更新如果中断,会导致 UI 不一致

 

一句话理解 Commit 阶段:

👉 “真正动 DOM,让页面发生变化”


🔥两个阶段的核心区别(面试重点)

阶段做什么是否可中断是否操作 DOM
Render计算 diff✅ 可以❌ 不可以
Commit更新 DOM❌ 不可以✅ 可以

为什么要分两阶段?(核心逻辑)

如果不分:

👉 React 一边算 diff,一边改 DOM

问题:

 

👉 分成两阶段后:

Render 阶段:

👉 可以慢慢算、可以暂停

Commit 阶段:

👉 一口气更新 DOM(保证一致性)


和 Fiber 的关系(关键串联)

Fiber 的作用就是:

👉 让 render 阶段可以被拆分成小任务

所以:


英文标准回答(面试版)

React updates are split into two phases:

1️⃣ Render Phase

In this phase, React:

👉 No DOM updates happen here.

👉 This phase is interruptible.

 

2️⃣ Commit Phase

In this phase, React:

👉 This phase is synchronous and not interruptible.


One-line summary(方便记忆)

👉 Chinese:

Render 阶段负责计算差异,Commit 阶段负责更新真实 DOM。

👉 English:

Render phase computes changes, commit phase applies them to the DOM.

 

Question 8(高频核心 useEffect在render还是commit阶段执行?)

useEffect 是在 render 阶段执行还是 commit 阶段执行?为什么?


标准答案(中文)

👉 useEffect 是在 commit 阶段之后执行的(异步执行)


正确执行顺序是:

React 更新流程是:

 

关键点(面试核心)

useEffect 不是 render,也不是 commit 内执行

👉 它是在:

DOM 更新完成之后,浏览器绘制之后执行


为什么要这样设计?

因为:

如果在 render 阶段执行 ❌

 

如果在 commit 阶段直接执行 ❌

 

所以 React 选择:

👉 commit 完 + 浏览器绘制后,再异步执行 effect


和 useLayoutEffect 的区别(高频追问)

Hook执行时机是否阻塞绘制
useLayoutEffectcommit 后、paint 前❌ 会阻塞
useEffectpaint 后✅ 不阻塞

一句话总结(必须背)

👉 中文:

useEffect 在 commit 阶段之后、浏览器绘制完成后异步执行。

👉 English:

useEffect runs after the commit phase and after the browser has painted.

 

Question 9(高频 + 难点 useEffect的依赖数组)

useEffect 为什么会有依赖数组?依赖是怎么被 React 记录和比较的?


标准面试回答(中文)

useEffect 的依赖数组,本质是 React 用来判断副作用是否需要重新执行的一种“浅比较机制”

 

1️⃣ React 如何“记住依赖”?

React 在内部会为每个 useEffect 保存一份数据:

👉 上一次的依赖数组(prevDeps)

结构类似:

 

2️⃣ 下一次 render 时做什么?

当组件重新 render:

React 会拿:

做比较:

👉 逐个用 Object.is 比较

 

3️⃣ 判断规则

 

4️⃣ 依赖数组三种情况(面试必问)

① 没有依赖数组

👉 每次更新都执行

② 空依赖数组

👉 只在首次挂载执行

③ 有依赖

👉 count 变化才执行

 

5️⃣ 为什么必须“浅比较”?

React 不做深比较,因为:

👉 所以只比较:

引用是否变化(Object.is)

面试加分点(很重要)

👉 React 判断依赖变化本质是:

基于 Fiber 上保存的 previous deps,通过 Object.is 做浅比较

Standard Answer (English)

The dependency array in useEffect is used by React to determine whether the effect should re-run.

1️⃣ How React stores dependencies

React stores previous dependencies internally on the Fiber:

 

2️⃣ Comparison process

On re-render, React compares:

using:

👉 Object.is (shallow comparison)

 

3️⃣ Rules

 

4️⃣ Why shallow comparison?

Because deep comparison would be too expensive.

So React uses:

reference equality check (Object.is)

一句话总结(面试必背)

👉 中文:

useEffect 通过在 Fiber 中保存上一次依赖数组,并用 Object.is 做浅比较来决定是否重新执行。

👉 English:

React compares previous and current dependencies using Object.is stored in Fiber to decide whether to re-run useEffect.

 

 

Question 10 (为什么if语句里面不能使用hooks)

React 为什么不能在 if 语句中使用 hooks?底层到底发生了什么问题?


标准面试回答(中文)

React 不能在 if / for / while 中调用 Hooks 的根本原因是:

👉 Hooks 在 React 内部是通过“调用顺序(index 顺序)”来存储和读取的

1️⃣ React 是怎么存 Hooks 的?

每个组件对应一个 Fiber,Fiber 上有一条 hooks 链表:

React 并不是用名字找 hook,而是:

👉 按调用顺序一个一个取

 

2️⃣ 正常情况(稳定顺序)

React 内部会记录:

👉 顺序完全固定

 

3️⃣ 如果写在 if 里

问题来了:

情况 A:flag = true

情况 B:flag = false

结果是什么?

👉 React 会“错位读取 hooks”

导致:

 

4️⃣ 本质原因(面试核心一句)

👉 React hooks 依赖的是:

稳定的调用顺序,而不是条件判断

 

5️⃣ 为什么 React 不用“名字映射”?

因为:


Standard Answer (English)

Hooks cannot be used inside conditions because React relies on the order of hook calls to maintain state.

 

1️⃣ How React stores hooks

Each component Fiber stores hooks as a linked list:

Hooks are accessed by call order, not by name.

 

2️⃣ Problem with conditional hooks

If hooks are inside conditions:

👉 This causes hooks to be mismatched

Result

State and effects will be assigned incorrectly, leading to bugs.

 

3️⃣ Core principle

Hooks must be called in the same order on every render.


一句话总结(面试必背)

👉 中文:

React 通过调用顺序管理 hooks,如果在条件语句中使用 hooks,会导致顺序错乱,从而导致状态错位。

👉 English:

React relies on consistent hook call order; conditional hooks break this order and cause state mismatches.

 

Question 11(进阶核心 Concurrent Rendering)

React 18 的 Concurrent Rendering(并发渲染)到底解决了什么问题?


标准面试答案(中文)

React 18 的 Concurrent Rendering(并发渲染)的核心目标是:

让 React 的渲染过程变成可中断、可调度的任务,从而提升 UI 响应性,避免长时间渲染阻塞主线程。

 

1️⃣ 旧架构的问题(React 17 及之前)

在传统 React 中:

👉 问题:

 

2️⃣ Concurrent Rendering 做了什么

React 18 引入并发机制后:

👉 把渲染变成“可中断任务”

React 可以:

 

3️⃣ 核心能力

✔️ Time slicing(时间切片)

把渲染拆成小块执行,而不是一次性执行完。

✔️ Priority scheduling(优先级调度)

不同任务有优先级:

✔️ 可丢弃渲染

低优先级更新可以被新的更新覆盖。

 

4️⃣ 解决的问题

 

一句话总结(必须背)

👉 中文:

Concurrent Rendering 让 React 渲染过程可中断并支持优先级调度,从而提升页面响应速度与流畅度。


🇨🇳 中文口语版

React 18 的并发渲染,其实就是让 React 的渲染过程不再是一次性做完。

以前如果组件很大,React 一旦开始渲染,就会一直执行到结束,中间是不能停的,所以页面可能会卡顿。

现在 React 可以把渲染拆成很多小任务,如果中间有更重要的事情,比如用户输入,它可以先暂停当前渲染,先去处理用户交互,再回来继续渲染。

所以它的核心就是让页面更流畅,避免因为渲染太重导致卡死。

 

🇺🇸 English spoken version

Concurrent Rendering in React 18 basically means that rendering is no longer a one-shot synchronous process.

In older React versions, once rendering starts, it runs to completion and cannot be interrupted, which can cause UI blocking or lag in large components.

Now React can break rendering into small chunks. If a more important task comes in, like user input, React can pause the rendering, handle the input first, and then resume rendering later.

So the main idea is to improve responsiveness and prevent the UI from freezing during heavy rendering work.

 

 

 

 

 

 

Question 12(核心进阶 react scheduler)

React Scheduler 是什么?它和 Concurrent Rendering 是什么关系?


标准面试答案(中文)

1️⃣ Scheduler 是什么?

React Scheduler 是 React 内部的任务调度系统,它的作用是:

👉 决定“哪个任务先执行、什么时候执行、能不能被打断”

它本质上做三件事:

 

2️⃣ 它解决什么问题?

在没有 Scheduler 的情况下:

Scheduler 的目标:

👉 让 React 可以“分时执行任务”,避免阻塞浏览器渲染和用户交互

 

3️⃣ Scheduler 和 Concurrent Rendering 的关系

👉 两者关系是:

可以理解为:

 

4️⃣ React 18 的核心升级点

Scheduler + Fiber + Lane Model:

👉 实现了:

 

5️⃣ 一句话总结(面试必背)

👉 中文:

Scheduler 是 React 的任务调度系统,用来管理更新优先级和执行时机,是实现 Concurrent Rendering 的核心基础设施。


🇨🇳 中文口语版

React 的 Scheduler 可以理解成 React 内部的“任务调度器”。

它的作用是决定哪些任务先执行,哪些任务可以延后,甚至哪些任务可以暂停。

在 React 18 之前,更新是同步执行的,一旦开始渲染就不能停,所以容易卡顿。

有了 Scheduler 之后,React 可以把任务分成不同优先级,比如用户输入是高优先级,UI 渲染是低优先级,这样它可以先处理更重要的任务,让页面更流畅。

所以 Scheduler 本质上是支撑并发渲染的底层调度系统。

 

🇺🇸 English spoken version

The React Scheduler is basically the internal task scheduling system of React.

It decides which updates should run first, which ones can be delayed, and which ones can be paused.

Before React 18, rendering was synchronous, so once it started, it couldn't be interrupted, which could cause UI blocking.

With the Scheduler, React can assign priorities to different tasks, like user input being high priority and UI rendering being lower priority. This allows React to keep the UI responsive.

So in short, the Scheduler is the core system that enables Concurrent Rendering.

 

 

 

 

 

Question 13(高频深水区 react lane)

React 的 Lane 模型是什么?它和 Scheduler 有什么区别?


标准面试答案(中文)

1️⃣ Lane 模型是什么?

Lane Model 是 React 18 中用于表示更新优先级的一种机制

👉 它本质是:

用“位掩码(bitmask)”来表示不同优先级的更新通道

你可以理解成:

每个 update 会被分配到一个或多个 lane。

 

2️⃣ Lane Model 解决什么问题?

在旧版本 React 中:

Lane Model 解决:

👉 精确区分不同更新优先级 + 支持并发合并

 

3️⃣ Lane 和 Scheduler 的区别

这是面试关键点:

概念作用
Scheduler决定“什么时候执行任务”
Lane决定“任务优先级属于哪一类”

👉 简单理解:

 

4️⃣ React 执行链路(重点)

 

5️⃣ 为什么用 Lane 而不是“数字优先级”?

因为 Lane:

👉 比“1、2、3 优先级”更灵活

 

6️⃣ 一句话总结(面试必背)

👉 中文:

Lane 模型是 React 用来表示更新优先级的位掩码系统,用于更精细地管理并发更新,而 Scheduler 负责调度这些更新的执行时机。


🇨🇳 中文口语版

Lane 模型可以理解成 React 用来表示“不同优先级任务”的一种方式。

它把不同类型的更新分配到不同的“车道”里面,每个 lane 代表一种优先级。

这样 React 在处理更新的时候,可以更清楚地知道哪些是高优先级,比如用户输入,哪些是低优先级,比如后台数据更新。

而 Scheduler 的作用是决定这些任务什么时候执行,Lane 是负责标记优先级,两者是配合关系。

 

🇺🇸 English spoken version

The Lane model in React is a way to represent update priorities using bitmasks.

You can think of it as different "lanes" for different priorities, where each update is assigned to one or more lanes.

This allows React to handle multiple updates with different priorities more efficiently.

The Scheduler decides when tasks should run, while the Lane model defines the priority of those tasks. They work together to enable concurrent rendering.

 

 

 

 

Question 14(终极难点 react18整个更新流程)

React 18 的整个更新流程(从 setState 到 commit)完整是怎么执行的?


标准面试答案(中文)

React 18 的更新流程可以拆成一条完整链路:

👉 setState → 生成 Update → Lane 标记优先级 → Scheduler 调度 → Render 阶段 → Reconcile → Commit 阶段

 

1️⃣ setState 阶段

当你调用:

React 会:

 

2️⃣ Lane 标记优先级

👉 每个 update 会被分配一个 Lane:

👉 作用:

标记这个更新“有多急”

 

3️⃣ Scheduler 调度阶段

Scheduler 会决定:

👉 “现在要不要执行这个更新?”

如果有更高优先级任务:

 

4️⃣ Render 阶段(可中断)

👉 React 开始执行:

⚠️ 特点:

 

5️⃣ Reconcile(协调)

👉 React 对比新旧 Fiber tree:

 

6️⃣ Commit 阶段(不可中断)

👉 真正执行 DOM 更新:

 

7️⃣ useEffect(最后执行)

👉 在 commit + paint 之后异步执行


一条完整链路(面试必背)

 

一句话总结(面试最重要)

👉 中文:

React 18 的更新流程是:setState 生成更新,通过 Lane 标记优先级,由 Scheduler 调度,在 Render 阶段计算差异,最后在 Commit 阶段更新 DOM。


🇨🇳 中文口语版

React 的更新流程可以理解成一条流水线。

当我们调用 setState 之后,React 会先创建一个更新任务,并给它分配一个优先级,也就是 Lane。

然后 Scheduler 会决定这个任务什么时候执行,如果当前有更重要的任务,比如用户输入,它可能会先处理那个。

接下来 React 进入 render 阶段,会重新执行组件函数,生成新的虚拟 DOM 并进行 diff,这一步是可以中断的。

最后进入 commit 阶段,把变化真正应用到 DOM 上,页面才会更新。

 

🇺🇸 English spoken version

The React update process is basically a pipeline.

When setState is called, React creates an update and assigns it a priority using the Lane model.

Then the Scheduler decides when to execute it, potentially delaying low-priority updates if there are more important ones like user input.

Next comes the render phase, where React re-renders components and performs reconciliation. This phase can be interrupted.

Finally, in the commit phase, React applies changes to the DOM, and the UI is updated.

 

 

 

Question 15(高阶核心 React Suspense)

React Suspense 是做什么的?它解决了什么问题?


标准面试答案(中文)

1️⃣ Suspense 是什么?

Suspense 是 React 提供的一种机制:

👉 用于“等待异步数据时,优雅地暂停组件渲染,并展示 fallback UI”

 

2️⃣ 它解决什么问题?

在 Suspense 之前:

如果数据没回来:

👉 Suspense 的目标是:

让 React 在“数据未准备好时暂停渲染”,而不是渲染错误或空状态

 

3️⃣ Suspense 的核心机制

当组件遇到“未完成的数据”(Promise)时:

React 会:

  1. 暂停当前组件渲染
  2. 找到最近的 <Suspense fallback>
  3. 渲染 fallback UI
  4. 数据完成后重新渲染真实 UI

 

4️⃣ 本质(面试关键)

👉 Suspense 本质是:

“Render 阶段的中断机制 + fallback UI 控制”

 

5️⃣ 在 Next.js 中的意义

在 App Router:

 

一句话总结(必须背)

👉 中文:

Suspense 让 React 在异步数据未完成时暂停渲染,并显示 fallback UI,从而实现更流畅的异步 UI 体验。


🇨🇳 中文口语版

Suspense 的作用可以理解成:当组件在等待数据的时候,React 不会直接渲染空内容或者报错,而是会先暂停这个组件的渲染,然后显示一个 fallback,比如 loading 状态。

等数据准备好了之后,再继续渲染真实内容。

所以它本质上就是让异步渲染变得更自然,不需要我们手动管理 loading 状态。

 

🇺🇸 English spoken version

Suspense is a mechanism in React that allows components to “pause rendering” when asynchronous data is not ready.

Instead of rendering empty or incomplete UI, React shows a fallback UI, like a loading state.

Once the data is ready, React resumes rendering the actual content.

So basically, it makes async UI handling much more natural and declarative.

 

 

 

Question 16(核心进阶 Suspense原理)

为什么 Suspense 可以“暂停渲染”?React 是怎么实现这个能力的?


标准面试答案(中文)

Suspense 之所以可以暂停渲染,是因为:

👉 React 在 render 阶段允许“抛出 Promise”,并通过捕获机制中断当前渲染流程

 

1️⃣ 核心机制:throw Promise

当组件在 render 中遇到未完成的数据时:

👉 React Query / Suspense-aware data source 会:

React 内部会:

 

2️⃣ Suspense boundary 的作用

👉 作用:

如果子组件“暂停”,就渲染 fallback

 

3️⃣ React 如何恢复?

当 Promise resolve:

👉 React 会:

  1. 标记这个更新完成
  2. 重新进入 render phase
  3. 继续执行之前暂停的 Fiber

 

4️⃣ 本质机制(面试核心)

Suspense 的底层不是“if loading”,而是:

👉 基于 render 阶段的异常控制流(throw/catch)机制

 

5️⃣ 为什么要用 throw Promise?

因为 React render 是:

👉 纯函数执行阶段

无法用普通 return 表达“暂停”

所以 React 用:

 

6️⃣ 和 Concurrent Rendering 的关系

Suspense 依赖:

👉 本质是:

Concurrent Rendering + 异步数据中断机制

一句话总结(必须背)

👉 中文:

Suspense 通过在 render 阶段“throw Promise”触发中断机制,使 React 能暂停渲染并显示 fallback UI,等数据完成后再恢复渲染。


🇨🇳 中文口语版

Suspense 能暂停渲染的原因,其实不是 React 在 render 里做了什么 if 判断,而是更底层的一种机制。

当组件在渲染过程中遇到还没准备好的数据时,它会抛出一个 Promise,这个行为会让 React 直接中断当前的渲染流程。

然后 React 会捕获这个 Promise,找到最近的 Suspense 边界,先渲染 fallback,比如 loading。

等 Promise 完成之后,React 会重新回到之前中断的地方继续渲染。

所以它本质上是 React 利用“throw/catch”实现的渲染中断机制。

 

🇺🇸 English spoken version

The reason Suspense can pause rendering is not just a conditional loading check.

Instead, during rendering, if some data is not ready, React actually throws a Promise, which interrupts the rendering process.

React catches this Promise, finds the nearest Suspense boundary, and renders the fallback UI, like a loading state.

Once the Promise resolves, React resumes rendering from where it was interrupted.

So basically, Suspense uses a throw/catch mechanism to interrupt and resume rendering.

 

 

Nextjs

Question 1(基础但必问 SSR / SSG / CSR)

Next.js 中 SSR、CSR、SSG 分别是什么?有什么区别?


标准面试回答(中文)

Next.js 中的 SSR、CSR、SSG 分别代表三种不同的渲染方式

 

1️⃣ CSR(Client-Side Rendering)

👉 客户端渲染

特点:

 

2️⃣ SSR(Server-Side Rendering)

👉 服务端渲染

特点:

 

3️⃣ SSG(Static Site Generation)

👉 静态生成

特点:

 

核心区别(面试关键)

类型发生时间是否每次请求计算性能
CSR浏览器运行时首屏慢
SSR每次请求时中等
SSG构建时最快

 

一句话总结(非常重要)

👉 中文:

CSR 在浏览器渲染,SSR 每次请求在服务器渲染,SSG 在构建时生成静态页面。


Standard Answer (English)

Next.js supports three rendering strategies:

 

1️⃣ CSR (Client-Side Rendering)

👉 Slower initial load, but good interactivity

 

2️⃣ SSR (Server-Side Rendering)

👉 Good SEO and fast first paint, but higher server cost

 

3️⃣ SSG (Static Site Generation)

👉 Fastest performance and CDN-friendly, but needs rebuild for updates

 

One-line summary

CSR renders in browser, SSR renders on request, SSG renders at build time.

 

 

Question 2(Next.js 核心原理 SSR / SSG的区别)

SSR 和 SSG 在 Next.js 中的本质区别是什么?(底层执行机制)

👉 提示你思考:


标准面试回答(中文)

SSR 和 SSG 的本质区别不是“都是在服务端渲染”,而是:

👉 HTML 是在什么时候生成的,以及生成结果能不能复用

 

1️⃣ SSR(Server-Side Rendering)

👉 每次请求都生成 HTML

执行过程:

  1. 用户访问页面
  2. Next.js 在服务器执行 React 组件
  3. 生成 HTML
  4. 返回给浏览器

⚠️ 特点:

 

2️⃣ SSG(Static Site Generation)

👉 在 build 时生成 HTML

执行过程:

  1. 项目 build
  2. Next.js 提前把页面渲染成 HTML
  3. 存成静态文件
  4. 用户请求直接返回文件

⚠️ 特点:

 

核心本质区别(面试关键)

维度SSRSSG
生成时间请求时构建时
是否每次计算
是否可缓存一般不可以(CDN)
性能最快
数据新鲜度实时非实时

 

一句话总结(必须背)

👉 中文:

SSR 是“每次请求生成页面”,SSG 是“提前构建好页面直接复用”。


Standard Answer (English)

The key difference between SSR and SSG is:

👉 when the HTML is generated and whether it is reused

 

1️⃣SSR (Server-Side Rendering)

👉 Fresh data, but higher cost

 

2️⃣SSG (Static Site Generation)

👉 Extremely fast and cacheable, but not always up to date

 

One-line summary

SSR generates HTML per request, SSG generates HTML at build time.

 

Question 3(Next.js 高频核心 hydration)

什么是 hydration?为什么 SSR 之后还需要 hydration?


标准面试回答(中文)

1️⃣ Hydration 是什么?

👉 Hydration(“注水”)指的是:

React 在 SSR 生成的静态 HTML 上“接管”并绑定事件的过程

关键点:

SSR 返回的 HTML:

 

👉 Hydration 做的事:

 

2️⃣ 为什么 SSR 之后必须 hydration?

因为 SSR 只是:

👉 “把 HTML 画出来”

但 React 应用需要:

👉 所以必须再跑一遍 React:

 

3️⃣ 没有 hydration 会怎样?

页面会变成:

👉 就像“只有壳子的网页”


4️⃣ Hydration 本质一句话

👉 React 会:

复用 SSR 的 DOM,而不是重新创建 DOM

 

面试加分点(很多人不知道)

Hydration 并不是“重新渲染页面”,而是:

对已有 DOM 做事件绑定 + diff 校验

如果 SSR 和客户端不一致,会出现:

👉 hydration mismatch(报错)


Standard Answer (English)

What is hydration?

Hydration is the process where React:

attaches event listeners and internal state to server-rendered HTML

 

Why is it needed?

SSR only produces static HTML:

👉 Hydration makes it interactive again by:


One-line summary

Hydration is the process of turning static SSR HTML into a fully interactive React app.

 

 

Question 4(高频 + 深水区 hydration和client render的区别)

Hydration 和重新渲染(client render)有什么区别?为什么不能直接重新渲染?


标准面试回答(中文)

1️⃣ 两者本质区别

✔️ Hydration(注水)

👉 复用 SSR 已经生成的 HTML,只“接管它”

做的事情:

 

❌ Client Re-render(重新渲染)

👉 完全重新生成 DOM

做的事情:

 

 

2️⃣ 为什么不能直接重新渲染?

因为 SSR 的核心目标是:

🚀 “让用户尽快看到页面”

如果直接 client re-render:

❌ 会发生:

  1. 服务器返回 HTML(SSR)
  2. 浏览器刚显示
  3. React 又删掉 DOM
  4. 再重新画一遍

👉 结果:

 

3️⃣ Hydration 的意义

👉 Hydration 的设计目标是:

尽可能复用 SSR 的结果,而不是推倒重来

 

4️⃣ 一个简单类比(面试很好用)

👉 SSR + Hydration:

服务器先帮你“装修好房子”,前端只是“开灯 + 接电”

👉 Client re-render:

先给你一个毛坯房,然后你自己重新装修一遍

 

5️⃣ 核心一句话(面试必背)

👉 中文:

Hydration 是复用 SSR 生成的 DOM 并进行事件绑定,而重新渲染是完全重建 DOM,两者成本和目的完全不同。


Standard Answer (English)

Difference

 

Why not re-render?

Because SSR already provides HTML, re-rendering would:

 

One-line summary

Hydration enhances SSR HTML instead of replacing it, while re-rendering rebuilds everything from scratch.

 

 

Question 5(Next.js 核心难点 server / client components 的区别)

Next.js App Router 中 Server Components 和 Client Components 有什么区别?


标准面试回答(中文)

在 Next.js App Router 中,组件默认是 Server Component(服务端组件),除非你显式写:

 

1️⃣ Server Components(默认)

👉 在 服务器执行

特点:

👉 本质:

只负责“生成 HTML”,不参与交互

 

2️⃣ Client Components("use client")

👉 在 浏览器执行

特点:

👉 本质:

负责“交互逻辑”

 

3️⃣ 核心区别(面试重点)

维度Server ComponentClient Component
执行环境ServerBrowser
是否有 JS bundle❌ 没有✅ 有
是否能用 hooks❌ 不可以✅ 可以
是否能访问 DB✅ 可以❌ 不可以
作用生成 HTML交互逻辑

 

4️⃣ 为什么 Next.js 要这样设计?

👉 核心目标:

减少客户端 JS,提高性能

如果全部都是 Client Component:

如果用 Server Component:

 

5️⃣ 一个非常重要的理解(面试加分)

👉 Next.js App Router 的理念是:

Server Components 负责“结构 + 数据”,Client Components 负责“交互”

 

6️⃣ 一句话总结(必须背)

👉 中文:

Server Components 在服务器执行,不包含交互逻辑;Client Components 在浏览器执行,负责交互和状态管理。


Standard Answer (English)

 

Server Components

👉 Used for data fetching and HTML generation

 

Client Components

 

One-line summary

Server Components run on the server for rendering, while Client Components run in the browser for interactivity.

 

 

Question 6(非常高频 server components 能完全取代 client components吗?)

Server Components 既然在服务器执行,那为什么不能直接完全替代 Client Components?


标准面试回答(中文)

Server Components 不能完全替代 Client Components,原因不只是“不能用浏览器 API”,而是因为:

👉 服务端和浏览器承担的是两类完全不同的职责:渲染 vs 交互

 

1️⃣ Server Components 的限制

你说的点是对的:

👉 因为它运行在:

Node.js server 环境

 

2️⃣ 更关键的原因(面试重点)

Server Components 不能处理“持续交互”

比如:

这些都需要:

👉 浏览器中的 runtime(React DOM)

 

3️⃣ React 本质是“双运行时模型”

Next.js App Router 是:

如果只有 Server Components:

👉 页面只能“生成一次”,无法更新 UI

 

4️⃣ 为什么不能只靠 server?

因为浏览器必须负责:

👉 server 做不到“持续响应 UI 变化”

 

5️⃣ 一个面试很好用的类比

👉 Server Components:

像“后端生成一份静态页面”

👉 Client Components:

像“前端让页面活起来(可以点、可以动)”

 

6️⃣ 一句话总结(必须背)

👉 中文:

Server Components 只能负责生成静态 UI,而 Client Components 负责浏览器端的交互和状态管理,两者职责不同,不能互相替代。


Standard Answer (English)

Server Components cannot fully replace Client Components because they serve different responsibilities:

 

Limitations

Core reason

Server Components only generate HTML, but cannot handle ongoing UI interactivity.

 

 

Why Client Components are needed

The browser is responsible for:

👉 This requires a client runtime.

 

One-line summary

Server Components generate static UI, while Client Components enable interactivity in the browser.

 

 

Question 7(Next.js 核心难点 缓存机制)

Next.js 中的缓存机制(cache / revalidate)是怎么工作的?


标准面试回答(中文)

Next.js 的缓存机制本质是:

👉 对“请求结果(HTML / 数据 / fetch 结果)进行分层缓存 + 可控失效(revalidate)”


1️⃣ Next.js 有哪几层缓存?

在 App Router 中,主要有三层:

① Data Cache(数据缓存)

👉 fetch 的结果可以被缓存

特点:

② Full Route Cache(路由缓存)

👉 整个页面的 HTML 会被缓存

③ Request Memoization(请求去重)

👉 同一个 render 过程中的重复请求会被合并

 

2️⃣ revalidate 是什么?

👉 控制“缓存多久过期”

① ISR(Incremental Static Regeneration)

👉 意思是:

每 60 秒可以重新生成一次页面

② 工作流程:

 

3️⃣ SSR / SSG / ISR 在缓存上的本质区别

模式是否缓存何时更新
SSR❌ 默认不缓存每次请求
SSG✅ 永久缓存build 时
ISR✅ 有缓存 + 定时更新revalidate

 

4️⃣ Next.js 为什么要做缓存?

👉 核心目的:

 

5️⃣ 一个非常重要的理解(面试加分)

👉 Next.js App Router 的本质:

不是“每次都渲染 React”,而是“尽可能复用缓存结果”

 

6️⃣ 一句话总结(必须背)

👉 中文:

Next.js 通过 Data Cache、Route Cache 和 Request Memoization 实现多层缓存,并通过 revalidate 控制缓存失效,实现性能优化与数据更新的平衡。


Standard Answer (English)

Next.js caching system is composed of multiple layers:

1️⃣ Data Cache

 

2️⃣ Full Route Cache

 

3️⃣ Request Memoization

 

4️⃣ revalidate (ISR)

 

One-line summary

Next.js uses multi-layer caching with revalidation to balance performance and data freshness.

 

 

Question 8(终极高频 app router解析)

Next.js 为什么 App Router 要基于 React Server Components?解决了什么问题?


标准面试回答(中文)

Next.js App Router 选择基于 React Server Components(RSC),核心是为了解决:

👉 传统 React 应用“客户端 JS 过重 + SSR hydration 成本高 + 数据获取混乱”的问题


1️⃣ 旧问题(Pages Router / 传统 SSR)

在 App Router 之前(Pages Router):

❌ 问题1:JS 太多

即使是 SSR:

👉 结果:

首屏快,但 JS 依然重

❌ 问题2:Hydration 成本高

👉 页面大时很慢

❌ 问题3:数据获取分散

👉 数据逻辑不统一

 

2️⃣ RSC 带来的核心变化

React Server Components 的核心思想:

👉 把“渲染逻辑”尽量放到 server,减少 client JS

 

3️⃣ App Router 的解决方案

✔️ 1. 减少 Client JS

Server Components:

👉 JS 体积大幅下降

✔️ 2. 消除部分 hydration

只有 Client Components 才需要 hydration:

👉 减少 React 在浏览器的工作量

✔️ 3. 数据获取更自然

直接在 Server Component 中:

👉 不再需要 getServerSideProps / getStaticProps

 

4️⃣ 本质总结(面试关键)

Next.js App Router + RSC 的本质是:

👉 重新划分 React 的职责边界

Server Components:

Client Components:

 

5️⃣ 一句话总结(必须背)

👉 中文:

Next.js 使用 React Server Components 是为了减少客户端 JavaScript、降低 hydration 成本,并统一服务端数据获取模型,从而提升性能和架构清晰度。


Standard Answer (English)

Next.js uses React Server Components to solve key issues in traditional SSR applications:

 

Problems in old architecture

 

What RSC changes

 

Core idea

Separate responsibilities: server handles rendering and data, client handles interactivity.

 

One-line summary

React Server Components reduce client-side JavaScript and hydration cost by moving rendering and data fetching to the server.