React 18 / 19 新特性
| 特性 | 说明 |
|---|---|
| 并发渲染(Concurrent) | 渲染可中断、可恢复、可丢弃,是下面所有能力的底层基础 |
| 自动批处理(Automatic Batching) | setTimeout/Promise/原生事件里的多次 setState 也会合并为一次渲染 |
useTransition / startTransition | 把非紧急更新标记为过渡任务,可被高优先级交互打断 |
useDeferredValue | 延迟某个值的更新,常用于搜索联想等场景 |
useId | 生成 SSR 前后一致的唯一 id,避免 hydration 不匹配 |
useSyncExternalStore | 供状态库订阅外部源,解决并发下的撕裂 |
createRoot | 新的根 API,启用并发特性(取代 ReactDOM.render) |
| Suspense + SSR 流式渲染 | 支持 renderToPipeableStream、选择性 hydration |
面试题:为什么 React 18 要把同步渲染改成并发? 同步渲染一旦开始无法中断,大组件树渲染会阻塞用户输入。并发渲染让 React 能在渲染过程中「让位」给高优先级任务(如打字、点击),渲染完再继续,从而保证交互流畅。
React 18 核心更新 (Concurrent Features)
一文解读 React 17 与 React 18 的更新变化
1.自动批量更新 (Automatic Batching)
在 React 18 之前,只有在 React 的合成事件(如 onClick)中才会批量更新 setState。而在 setTimeout、Promise 或原生事件中连续多次 setState,会导致多次 render。
React 18:无论在哪里(包括 setTimeout 和异步回调),只要处于同一个宏任务或微任务的执行栈中,多次 setState 都会被合并为一次更新。
原理解析:为什么 React 18 能做到全场景的自动批处理?
- React 17 时代:React 依赖内部的一个全局变量
isBatchingUpdates。只有在进入 React 自身的合成事件回调前,才会把这个变量设为true。但如果你的setState写在了setTimeout里面,等定时器触发时,外层的同步事件代码早就跑完了,isBatchingUpdates已经恢复成了false,所以后续每个setState都会立即触发一次同步渲染。- React 18 时代:抛弃了通过全局变量强行包裹的方式,转而引入了全新的 Lane(车道)优先级调度机制。当你调用
setState时,React 不再立刻去渲染,而是给这次更新分配一个优先级,并向浏览器的微任务队列 (Microtask Queue) 中注册一个调度任务。如果你在同一个setTimeout里连续调了 3 次setState,React 只是把 3 个更新任务塞进了同一个队列(赋予相同的优先级)。等这轮宏任务里的同步代码跑完,JS 引擎去清空微任务队列时,React 才会把这 3 个状态合并,统一执行一次渲染。
2.Concurrent Mode (并发模式)
这是 React 18 最重大的底层架构变更。React 可以在后台准备新的屏幕内容而不阻塞主线程。
useTransition/startTransition: 将非紧急的 UI 更新标记为“过渡任务(Transition)”。如果用户在此期间进行了紧急交互(如输入框打字),过渡任务的渲染会被打断,优先响应用户输入,彻底解决输入卡顿问题。
3.其他新特性
useDeferredValue:与useTransition类似,用于延迟某个非紧急值的更新。Suspense真正支持了 SSR 流式渲染。
React 19 新特性(重点)
截至 2026 年 React 19 已是主流版本,是当前面试的热点。
1. Actions 与表单
把「数据变更 + pending 状态 + 错误处理 + 乐观更新」标准化。表单的 action 可以直接传一个(异步)函数。
useActionState(原useFormState):管理 action 的状态、返回值与 pending。
const [error, submitAction, isPending] = useActionState(
async (prevState, formData) => {
const err = await updateName(formData.get("name"));
if (err) return err;
redirect("/profile");
return null;
},
null,
);
return (
<form action={submitAction}>
<input name="name" />
<button disabled={isPending}>提交</button>
</form>
);
useFormStatus:在表单子组件里直接读取父<form>的提交状态(无需层层传 props)。
2. useOptimistic(乐观更新)
在异步请求返回前先「乐观地」更新 UI,请求失败/完成后再以真实结果为准。
const [optimisticMessages, addOptimistic] = useOptimistic(
messages,
(state, newMsg) => [...state, { text: newMsg, sending: true }],
);
3. use API
可在渲染中读取 Promise 或 Context,配合 Suspense 实现更顺滑的数据读取;与其他 Hook 不同,use 可以在条件语句里调用。
function Comment({ commentPromise }) {
const comment = use(commentPromise); // 会触发最近的 Suspense
return <p>{comment}</p>;
}
4. 其他改进
ref作为普通 prop:函数组件可直接接收ref,不再强制forwardRef。<Context>直接当 Provider:<ThemeContext value={...}>,无需.Provider。- 文档元数据:组件内直接写
<title>/<meta>/<link>,React 会自动提升到<head>。 - 资源预加载:
preload/preinit等 API。 - 改进的 hydration 错误提示。
React Server Components(RSC)
面试题:什么是 Server Components?解决什么问题?
- 服务端组件:只在服务端运行、不打包进客户端 bundle 的组件,可直接访问数据库/文件系统,零客户端 JS 体积,对首屏和 SEO 友好。
- 与 Client Components(
"use client"标记,可用状态和事件)配合使用。 - 是 Next.js App Router 的核心模型;面试常问「RSC 与 SSR 的区别」:SSR 是把组件渲染成 HTML 字符串后再 hydration,组件代码仍会下发到客户端;RSC 的服务端组件代码完全不下发,只传渲染结果(特殊序列化格式)。