React 18 新特性详解
更新: 8/6/2025 字数: 0 字 时长: 0 分钟
React 18 是 React 的一个重要版本,引入了许多令人兴奋的新功能和改进,旨在提升应用性能和开发体验。本文将详细介绍 React 18 的核心特性。
React 18 主要更新概览
React 18 带来了以下重要更新:
- 全新的 Root API
- 自动批处理(Automatic Batching)
- 并发渲染(Concurrent Rendering)
- Suspense 的改进
- 新的 Hooks:useId、useTransition、useDeferredValue
- 流式服务端渲染(Streaming SSR)
- flushSync 强制同步更新
- useSyncExternalStore 外部状态同步
- 新的 Render API
React 架构演进
在深入了解 React 18 的新特性之前,让我们先了解一下 React 的架构演进历程。从最早的版本到当前的 v18,React 经历了重大的架构变化。
两种核心架构
Stack Reconciler(老架构)
- 采用不可中断的递归方式更新
- 在 React v15 及之前版本中使用
Fiber Reconciler(新架构)
- 采用可中断的遍历方式更新
- 从 React v16 开始引入
React 版本的四种情况
基于这两种架构和并发更新的启用情况,市面上的 React 版本可以分为四种情况:
老架构(v15及之前版本)
- 使用 Stack Reconciler
- 不支持并发更新
新架构,未开启并发更新,与情况1行为一致(v16、v17 默认属于这种情况)
- 使用 Fiber Reconciler
- 未启用并发更新功能
- 行为与老架构相似
新架构,未开启并发更新,但是启用了并发模式和一些新功能(v18 默认属于这种情况)
- 使用 Fiber Reconciler
- 未启用并发更新
- 启用了一些新功能,如 Automatic Batching
新架构,开启并发模式,开启并发更新
- 使用 Fiber Reconciler
- 启用并发更新
- 可以使用所有并发特性
并发模式与并发更新的关系
在 React 18 中,一个重要的概念澄清是:开启并发模式并不等同于开启并发更新。
在 React 17 的一些实验性功能中,开启并发模式确实会开启并发更新。但在 React 18 正式版中,由于官方策略调整,React 不再依赖并发模式来开启并发更新。
换句话说:开启了并发模式,并不一定开启了并发更新!
一句话总结:在 React 18 中,不再有多种模式,而是以是否使用并发特性作为是否开启并发更新的依据。
并发特性指的是开启并发模式后才能使用的特性,比如:
- useDeferredValue
- useTransition
全新的 Root API
React 18 引入了新的 Root API,使用 createRoot
替代了旧的 ReactDOM.render
方法:
// React 18 新方式
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
// React 17 旧方式
import ReactDOM from 'react-dom';
ReactDOM.render(<App />, document.getElementById('root'));
新的 Root API 提供了更好的性能和更多功能,特别是在并发渲染方面。
自动批处理(Automatic Batching)
React 18 扩展了自动批处理功能,将多个状态更新合并为单次重新渲染,以提高性能:
function MyComponent() {
const [count, setCount] = useState(0);
const [flag, setFlag] = useState(false);
function handleClick() {
// React 18 会自动批处理这些更新
setCount(c => c + 1);
setFlag(f => !f);
// 即使在 Promise 中也会自动批处理
fetch('/api/data').then(() => {
setCount(c => c + 1);
setFlag(f => !f);
});
}
return (
<div>
<p>Count: {count}</p>
<p>Flag: {String(flag)}</p>
<button onClick={handleClick}>Update</button>
</div>
);
}
在 React 17 中,只有在 React 事件处理程序内的更新才会被批处理,而在 Promise、setTimeout 等异步回调中不会。React 18 则会自动批处理所有这些更新。
并发渲染(Concurrent Rendering)
并发渲染是 React 18 的核心特性,它允许 React 同时准备多个版本的 UI,并在后台渲染更新,从而在渲染过程中保持应用的响应性。
并发渲染的优势
- 中断渲染:React 可以在需要时中断渲染工作
- 优先级调度:高优先级更新可以中断低优先级更新
- 保持响应性:即使在大型更新期间,应用也能保持响应
使用并发特性
import { useTransition } from 'react';
function TabContainer() {
const [isPending, startTransition] = useTransition();
const [tab, setTab] = useState('about');
function selectTab(nextTab) {
startTransition(() => {
setTab(nextTab);
});
}
return (
<div>
<button onClick={() => selectTab('about')}>About</button>
<button onClick={() => selectTab('posts')}>Posts</button>
<button onClick={() => selectTab('contact')}>Contact</button>
{isPending ? <Spinner /> : <TabContent tab={tab} />}
</div>
);
}
Suspense 改进
React 18 对 Suspense 进行了重大改进,使其支持更多场景:
组件级 Suspense
import { Suspense } from 'react';
function MyComponent() {
return (
<div>
<Suspense fallback={<Spinner />}>
<ComponentThatSuspends />
</Suspense>
</div>
);
}
流式 HTML 和选择性注水
React 18 改进了服务端渲染,支持流式 HTML 和选择性注水:
// 服务端
import { renderToPipeableStream } from 'react-dom/server';
function handler(req, res) {
const { pipe } = renderToPipeableStream(<App />, {
onShellReady() {
res.setHeader('content-type', 'text/html');
pipe(res);
},
onError(err) {
res.statusCode = 500;
console.error(err);
}
});
}
新的 Hooks
React 18 引入了几个新的 Hooks,以支持并发渲染和改进用户体验。
useId Hook
useId
是一个用于生成唯一 ID 的 Hook,特别适用于服务端渲染:
import { useId } from 'react';
function Checkbox() {
const id = useId();
return (
<>
<label htmlFor={id}>Do you like React?</label>
<input id={id} type="checkbox" name="react"/>
</>
);
}
function App() {
return (
<>
<Checkbox />
<Checkbox />
</>
);
}
useTransition Hook
useTransition
允许你将某些更新标记为过渡更新,从而不会阻塞紧急更新:
import { useState, useTransition } from 'react';
function App() {
const [isPending, startTransition] = useTransition();
const [count, setCount] = useState(0);
function handleClick() {
startTransition(() => {
setCount(c => c + 1);
});
}
return (
<div>
{isPending && <Spinner />}
<button onClick={handleClick}>{count}</button>
</div>
);
}
useDeferredValue Hook
useDeferredValue
允许你推迟重新渲染树的一部分:
import { useState, useDeferredValue } from 'react';
function SearchResults({ query }) {
const deferredQuery = useDeferredValue(query);
const isStale = query !== deferredQuery;
return (
<div className={isStale ? 'opacity-50' : ''}>
<Results query={deferredQuery} />
</div>
);
}
function App() {
const [query, setQuery] = useState('');
return (
<>
<input value={query} onChange={e => setQuery(e.target.value)} />
<SearchResults query={query} />
</>
);
}
flushSync 强制同步更新
flushSync
是 React 18 中引入的一个函数,它允许你强制 React 同步刷新所有挂起的工作并更新 DOM。这在某些特殊场景下非常有用,比如在需要立即读取 DOM 更新后的值时。
import { flushSync } from 'react-dom';
function MyComponent() {
const [count, setCount] = useState(0);
function handleClick() {
// 正常的异步更新
setCount(c => c + 1);
// 在某些场景下需要同步更新
flushSync(() => {
setCount(c => c + 1);
});
// 此时 DOM 已经更新完成
console.log(document.getElementById('counter').textContent);
}
return (
<div>
<p id="counter">{count}</p>
<button onClick={handleClick}>Increase</button>
</div>
);
}
使用 flushSync
的场景包括:
- 与第三方库集成时需要同步更新 DOM
- 在事件处理程序中需要立即读取更新后的 DOM 值
- 需要确保某些更新在浏览器重排之前完成
需要注意的是,过度使用 flushSync
可能会影响应用性能,因为它会中断并发渲染的优势。
useSyncExternalStore 外部状态同步
useSyncExternalStore
是 React 18 中引入的一个 Hook,用于解决外部状态存储(如 Redux、MobX 或浏览器 API)与 React 并发渲染特性之间的兼容性问题。
import { useSyncExternalStore } from 'react';
// 外部存储示例
const store = {
state: { count: 0 },
listeners: new Set(),
setState(newState) {
this.state = { ...this.state, ...newState };
this.listeners.forEach(listener => listener());
},
subscribe(listener) {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
},
getSnapshot() {
return this.state;
}
};
function useStore() {
return useSyncExternalStore(
store.subscribe, // 订阅函数
store.getSnapshot // 获取快照函数
);
}
function Counter() {
const { count } = useStore();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => store.setState({ count: count + 1 })}>
Increase
</button>
</div>
);
}
useSyncExternalStore
接收三个参数:
subscribe
:订阅函数,用于注册状态变化的监听器getSnapshot
:获取当前状态快照的函数getServerSnapshot
(可选):服务端渲染时获取快照的函数
这个 Hook 确保即使在 React 的并发渲染模式下,外部状态也能正确地与组件同步。
流式服务端渲染(Streaming SSR)
React 18 引入了两个新的服务端 API,支持流式渲染:
renderToPipeableStream
用于 Node 环境:
import { renderToPipeableStream } from 'react-dom/server';
import App from './App';
function handler(req, res) {
res.setHeader('Content-Type', 'text/html');
const { pipe } = renderToPipeableStream(
<App />,
{
onShellReady() {
// 第一批 HTML 准备就绪
pipe(res);
},
onShellError(error) {
// 发生错误时的处理
res.statusCode = 500;
res.send('<h1>An error occurred</h1>');
},
onAllReady() {
// 所有内容准备就绪(可选)
},
onError(err) {
// 记录错误
console.error(err);
}
}
);
}
renderToReadableStream
用于边缘运行时(如 Cloudflare Workers):
import { renderToReadableStream } from 'react-dom/server';
import App from './App';
export default async function handler(request) {
const stream = await renderToReadableStream(
<App />,
{
onError(err) {
console.error(err);
}
}
);
return new Response(stream, {
headers: { 'Content-Type': 'text/html' }
});
}
选择性注水(Selective Hydration)
React 18 支持选择性注水,允许组件在准备就绪时立即注水,而不是等待整个应用:
// 在服务端渲染时,React 会自动将 Suspense 边界注入到 HTML 中
// 在客户端,React 会优先注水交互式组件
function App() {
return (
<div>
<Sidebar />
<Suspense fallback={<Spinner />}>
<Content />
</Suspense>
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
</div>
);
}
与 React 17 的对比
特性 | React 17 | React 18 |
---|---|---|
Root API | ReactDOM.render | createRoot |
自动批处理 | 仅限事件处理程序 | 所有更新 |
并发渲染 | 不支持 | 支持 |
Suspense | 仅限 lazy | 支持更多场景 |
流式 SSR | 不支持 | 支持 |
选择性注水 | 不支持 | 支持 |
flushSync | 不支持 | 支持 |
useSyncExternalStore | 不支持 | 支持 |
升级到 React 18
升级到 React 18 通常很简单,但需要注意以下几点:
更新 Root API:
jsx// 从 ReactDOM.render(<App />, document.getElementById('root')); // 改为 const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />);
处理自动批处理可能导致的行为变化
更新相关依赖项到兼容版本
性能优化建议
使用 useTransition 处理大型更新:
jsxconst [isPending, startTransition] = useTransition();
利用 useDeferredValue 优化搜索:
jsxconst deferredQuery = useDeferredValue(query);
适当使用 Suspense 分割加载状态:
jsx<Suspense fallback={<Spinner />}> <ExpensiveComponent /> </Suspense>
总结
React 18 是 React 发展历程中的一个重要里程碑,引入了并发渲染、自动批处理、新的 Hooks 等一系列重要特性。这些更新不仅提升了应用性能,还改善了开发体验。通过采用 React 18 的新特性,开发者可以构建更流畅、更响应迅速的用户界面。
升级到 React 18 是值得的,特别是对于需要处理复杂交互和大量数据的应用。并发渲染和流式 SSR 等特性可以帮助应用在保持响应性的同时处理更复杂的 UI 更新。