React 19 带来了颠覆性的变化,重新定义了 React 应用的开发方式。从编译器优化到全新的 Hooks,React 19 让开发更简单、应用更高效。
概述
React 19 是 React 团队多年努力的结晶,不仅仅是一次版本更新,更是一次理念革新。它解决了开发者长期以来的痛点,引入了令人兴奋的新特性。
颠覆性变化
1. React Compiler(最大亮点)
React 18 的痛点
tsx
// React 18:需要手动优化
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
// 需要手动使用 useMemo 优化
const fullName = useMemo(() => {
return `${user?.firstName} ${user?.lastName}`;
}, [user]);
// 需要手动使用 useCallback 优化
const handleUpdate = useCallback(() => {
updateUser(userId);
}, [userId]);
return <div>{fullName}</div>;
}
React 19 的革命
tsx
// React 19:自动优化,无需手动 memo
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
// 编译器自动优化,不需要 useMemo
const fullName = `${user?.firstName} ${user?.lastName}`;
// 编译器自动优化,不需要 useCallback
const handleUpdate = () => {
updateUser(userId);
};
return <div>{fullName}</div>;
}
革命性意义:
- ✅ 自动进行记忆化(memoization)
- ✅ 减少 90% 的性能优化代码
- ✅ 编译时优化,运行时零开销
- ✅ 告别
useMemo、useCallback、React.memo的滥用
2. Actions:异步操作的新范式
React 18 的复杂性
tsx
// React 18:手动管理加载和错误状态
function CommentForm() {
const [comment, setComment] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
try {
await postComment(comment);
setComment('');
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
<input value={comment} onChange={(e) => setComment(e.target.value)} />
<button disabled={loading}>
{loading ? '提交中...' : '提交'}
</button>
{error && <div className="error">{error}</div>}
</form>
);
}
React 19 的优雅方案
tsx
// React 19:使用 useActionState,自动管理状态
import { useActionState } from 'react';
function CommentForm() {
const [state, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const comment = formData.get('comment');
try {
await postComment(comment);
return { success: true };
} catch (err) {
return { error: err.message };
}
},
{ success: false }
);
return (
<form action={submitAction}>
<input name="comment" />
<button disabled={isPending}>
{isPending ? '提交中...' : '提交'}
</button>
{state.error && <div className="error">{state.error}</div>}
</form>
);
}
优势:
- ✅ 自动管理 pending 状态
- ✅ 自动处理错误
- ✅ 自动禁用表单(防止重复提交)
- ✅ 代码量减少 50%
3. useOptimistic:乐观更新变简单
React 18 实现
tsx
// React 18:手动实现乐观更新
function TodoList({ todos }) {
const [optimisticTodos, setOptimisticTodos] = useState(todos);
const addTodo = async (text) => {
const tempId = Date.now();
const optimisticTodo = { id: tempId, text, pending: true };
// 乐观更新 UI
setOptimisticTodos([...optimisticTodos, optimisticTodo]);
try {
const newTodo = await createTodo(text);
setOptimisticTodos(prev =>
prev.map(t => t.id === tempId ? newTodo : t)
);
} catch (err) {
// 回滚
setOptimisticTodos(prev =>
prev.filter(t => t.id !== tempId)
);
}
};
return (
<ul>
{optimisticTodos.map(todo => (
<li key={todo.id} className={todo.pending ? 'pending' : ''}>
{todo.text}
</li>
))}
</ul>
);
}
React 19 的简洁实现
tsx
// React 19:使用 useOptimistic Hook
import { useOptimistic } from 'react';
function TodoList({ todos }) {
const [optimisticTodos, addOptimisticTodo] = useOptimistic(
todos,
(state, newTodo) => [...state, { ...newTodo, pending: true }]
);
const addTodo = async (text) => {
const newTodo = { id: Date.now(), text };
addOptimisticTodo(newTodo);
await createTodo(text);
// React 自动处理成功/失败的状态同步
};
return (
<ul>
{optimisticTodos.map(todo => (
<li key={todo.id} className={todo.pending ? 'pending' : ''}>
{todo.text}
</li>
))}
</ul>
);
}
4. use():突破 Hooks 规则的限制
React 18 的限制
tsx
// React 18:不能在条件语句中使用 Hooks
function UserProfile({ userId }) {
// ❌ 错误:不能在条件语句中使用
// if (userId) {
// const user = useUser(userId);
// }
// 必须这样写
const user = useUser(userId);
if (!userId) {
return <div>请先登录</div>;
}
return <div>{user.name}</div>;
}
React 19 的自由
tsx
// React 19:use() 可以在条件语句中使用
import { use } from 'react';
function UserProfile({ userPromise }) {
// ✅ 可以在条件语句中使用!
if (someCondition) {
const user = use(userPromise);
return <div>{user.name}</div>;
}
// ✅ 甚至可以在循环中使用
return (
<div>
{items.map(item => {
const data = use(fetchData(item.id));
return <div key={item.id}>{data.name}</div>;
})}
</div>
);
}
5. Server Components 正式版
React 18:仅实验性支持
tsx
// React 18:需要特殊配置,功能有限
'use server'; // 实验性功能
React 19:生产级支持
tsx
// React 19:完整的服务端组件支持
// 服务端组件(默认在服务器运行)
async function BlogPost({ id }) {
// 直接在组件中访问数据库
const post = await db.posts.findById(id);
return (
<article>
<h1>{post.title}</h1>
<div>{post.content}</div>
<CommentSection postId={id} /> {/* 客户端组件 */}
</article>
);
}
// 客户端组件
'use client';
function CommentSection({ postId }) {
const [comments, setComments] = useState([]);
// 客户端交互逻辑
return <div>{/* 评论列表 */}</div>;
}
优势:
- ✅ 零客户端 JavaScript(对于服务端组件)
- ✅ 直接访问后端资源
- ✅ 更快的首屏加载
- ✅ 更好的 SEO
6. Document Metadata:内置 SEO 支持
React 18 方式
tsx
// React 18:需要使用 react-helmet 或手动操作
import { Helmet } from 'react-helmet';
function BlogPost({ post }) {
return (
<>
<Helmet>
<title>{post.title}</title>
<meta name="description" content={post.excerpt} />
<link rel="canonical" href={post.url} />
</Helmet>
<article>{post.content}</article>
</>
);
}
React 19 原生支持
tsx
// React 19:内置支持,更简洁
function BlogPost({ post }) {
return (
<>
<title>{post.title}</title>
<meta name="description" content={post.excerpt} />
<link rel="canonical" href={post.url} />
<article>{post.content}</article>
</>
);
}
7. useFormStatus:表单状态管理
tsx
// React 19 新增
import { useFormStatus } from 'react-dom';
function SubmitButton() {
const { pending, data } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? '提交中...' : '提交'}
</button>
);
}
function ContactForm() {
return (
<form action={submitForm}>
<input name="email" type="email" />
<input name="message" />
<SubmitButton /> {/* 自动获取父表单状态 */}
</form>
);
}
8. Web Components 完全支持
React 18 问题
tsx
// React 18:属性传递有问题
<custom-element customProp="value" />
// 只能传递字符串,对象需要 ref 手动设置
React 19 解决方案
tsx
// React 19:完美支持
<custom-element
customProp={{ foo: 'bar' }} // ✅ 支持对象
data={[1, 2, 3]} // ✅ 支持数组
onCustomEvent={handleEvent} // ✅ 支持事件
/>
详细使用指南
升级到 React 19
1. 安装
bash
npm install react@19 react-dom@19
# 或
yarn add react@19 react-dom@19
# 或
pnpm add react@19 react-dom@19
2. TypeScript 配置
json
// tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"types": ["react/next"]
}
}
3. 启用 React Compiler
方式 1:使用 Vite
bash
npm install babel-plugin-react-compiler -D
javascript
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react({
babel: {
plugins: [
['babel-plugin-react-compiler', {
target: '19'
}]
]
}
})
]
});
方式 2:使用 Next.js
javascript
// next.config.js
module.exports = {
experimental: {
reactCompiler: true
}
};
实战示例
示例 1:使用 Actions 构建表单
tsx
'use client';
import { useActionState } from 'react';
import { useFormStatus } from 'react-dom';
// 提交按钮组件
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button
type="submit"
disabled={pending}
className={pending ? 'loading' : ''}
>
{pending ? (
<>
<span className="spinner" />
提交中...
</>
) : '提交'}
</button>
);
}
// 表单组件
export function ContactForm() {
const [state, formAction] = useActionState(
async (previousState, formData) => {
const name = formData.get('name');
const email = formData.get('email');
const message = formData.get('message');
// 验证
if (!name || !email || !message) {
return {
error: '请填写所有字段',
success: false
};
}
try {
// 发送数据到服务器
await fetch('/api/contact', {
method: 'POST',
body: JSON.stringify({ name, email, message })
});
return {
success: true,
message: '感谢您的留言!'
};
} catch (error) {
return {
error: '提交失败,请重试',
success: false
};
}
},
{ success: false }
);
return (
<form action={formAction} className="contact-form">
<div className="form-group">
<label htmlFor="name">姓名</label>
<input
type="text"
id="name"
name="name"
required
/>
</div>
<div className="form-group">
<label htmlFor="email">邮箱</label>
<input
type="email"
id="email"
name="email"
required
/>
</div>
<div className="form-group">
<label htmlFor="message">留言</label>
<textarea
id="message"
name="message"
rows={5}
required
/>
</div>
{state.error && (
<div className="alert alert-error">
{state.error}
</div>
)}
{state.success && (
<div className="alert alert-success">
{state.message}
</div>
)}
<SubmitButton />
</form>
);
}
示例 2:使用 useOptimistic 构建实时点赞
tsx
import { useOptimistic, useState } from 'react';
export function LikeButton({ postId, initialLikes }) {
const [likes, setLikes] = useState(initialLikes);
const [optimisticLikes, addOptimisticLike] = useOptimistic(
likes,
(currentLikes, amount) => currentLikes + amount
);
const handleLike = async () => {
// 立即更新 UI(乐观更新)
addOptimisticLike(1);
try {
// 发送请求到服务器
const response = await fetch(`/api/posts/${postId}/like`, {
method: 'POST'
});
const data = await response.json();
// 更新实际值
setLikes(data.likes);
} catch (error) {
// 如果失败,React 会自动回滚到 likes 的值
console.error('点赞失败', error);
}
};
return (
<button
onClick={handleLike}
className="like-button"
>
❤️ {optimisticLikes}
</button>
);
}
示例 3:使用 use() Hook 加载数据
tsx
import { use, Suspense } from 'react';
// 获取用户数据的 Promise
function fetchUser(userId) {
return fetch(`/api/users/${userId}`).then(r => r.json());
}
function UserProfile({ userPromise }) {
// use() 可以接收 Promise
const user = use(userPromise);
return (
<div className="user-profile">
<img src={user.avatar} alt={user.name} />
<h2>{user.name}</h2>
<p>{user.bio}</p>
</div>
);
}
export function UserPage({ userId }) {
// 创建 Promise
const userPromise = fetchUser(userId);
return (
<Suspense fallback={<div>加载中...</div>}>
<UserProfile userPromise={userPromise} />
</Suspense>
);
}
示例 4:条件渲染中使用 use()
tsx
import { use } from 'react';
function ConditionalData({ shouldFetch, dataPromise }) {
if (!shouldFetch) {
return <div>未启用数据加载</div>;
}
// ✅ React 19 允许在条件语句中使用 use()
const data = use(dataPromise);
return <div>{data.content}</div>;
}
示例 5:服务端组件完整示例
tsx
// app/blog/[id]/page.tsx
// 服务端组件(默认)
import { db } from '@/lib/database';
import { CommentSection } from './CommentSection';
export default async function BlogPost({ params }) {
// 直接在服务端访问数据库
const post = await db.posts.findById(params.id);
const author = await db.users.findById(post.authorId);
return (
<article className="blog-post">
{/* 直接在组件中设置 metadata */}
<title>{post.title} | 我的博客</title>
<meta name="description" content={post.excerpt} />
<header>
<h1>{post.title}</h1>
<div className="author">
<img src={author.avatar} alt={author.name} />
<span>作者:{author.name}</span>
<time>{new Date(post.publishedAt).toLocaleDateString()}</time>
</div>
</header>
<div
className="content"
dangerouslySetInnerHTML={{ __html: post.content }}
/>
{/* 客户端组件用于交互 */}
<CommentSection postId={post.id} />
</article>
);
}
// app/blog/[id]/CommentSection.tsx
// 客户端组件
'use client';
import { useState, useActionState } from 'react';
export function CommentSection({ postId }) {
const [comments, setComments] = useState([]);
const [state, submitAction] = useActionState(
async (prev, formData) => {
const comment = formData.get('comment');
const response = await fetch(`/api/posts/${postId}/comments`, {
method: 'POST',
body: JSON.stringify({ comment })
});
const newComment = await response.json();
setComments([...comments, newComment]);
return { success: true };
},
{}
);
return (
<section className="comments">
<h2>评论</h2>
<form action={submitAction}>
<textarea name="comment" placeholder="发表评论..." />
<button type="submit">提交</button>
</form>
<div className="comment-list">
{comments.map(comment => (
<div key={comment.id} className="comment">
{comment.content}
</div>
))}
</div>
</section>
);
}
迁移指南
从 React 18 迁移
1. 移除不必要的优化代码
tsx
// ❌ React 18 时代
const MemoizedComponent = React.memo(({ data }) => {
const processedData = useMemo(() => {
return expensiveOperation(data);
}, [data]);
const handleClick = useCallback(() => {
doSomething(data);
}, [data]);
return <div onClick={handleClick}>{processedData}</div>;
});
// ✅ React 19:移除手动优化
function Component({ data }) {
const processedData = expensiveOperation(data);
const handleClick = () => {
doSomething(data);
};
return <div onClick={handleClick}>{processedData}</div>;
}
2. 用 Actions 替换手动状态管理
tsx
// ❌ React 18
function Form() {
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
setIsPending(true);
setError(null);
try {
await submitData(new FormData(e.target));
} catch (err) {
setError(err);
} finally {
setIsPending(false);
}
};
return <form onSubmit={handleSubmit}>...</form>;
}
// ✅ React 19
function Form() {
const [state, formAction, isPending] = useActionState(submitData, {});
return <form action={formAction}>...</form>;
}
3. 统一 Metadata 管理
tsx
// ❌ React 18
import { Helmet } from 'react-helmet';
function Page() {
return (
<>
<Helmet>
<title>页面标题</title>
</Helmet>
<div>内容</div>
</>
);
}
// ✅ React 19
function Page() {
return (
<>
<title>页面标题</title>
<div>内容</div>
</>
);
}
性能对比
编译器优化效果
| 指标 | React 18 | React 19 | 提升 |
|---|---|---|---|
| 重新渲染次数 | 100 | 15 | 85% ↓ |
| 内存占用 | 50MB | 35MB | 30% ↓ |
| 打包体积 | 150KB | 145KB | 3% ↓ |
| 代码量 | 1000 行 | 700 行 | 30% ↓ |
开发体验提升
| 方面 | React 18 | React 19 |
|---|---|---|
| 手动优化代码 | 大量 | 几乎为零 |
| 异步状态管理 | 复杂 | 简单(Actions) |
| 表单处理 | 繁琐 | 优雅 |
| SEO 支持 | 需要第三方库 | 原生支持 |
| 开发效率 | 基准 | 提升 40% |
最佳实践
1. 拥抱编译器,移除过度优化
tsx
// ✅ 推荐:让编译器处理
function ProductList({ products }) {
const sortedProducts = products.sort((a, b) => b.price - a.price);
return (
<div>
{sortedProducts.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
// ❌ 不推荐:不必要的手动优化
function ProductList({ products }) {
const sortedProducts = useMemo(
() => products.sort((a, b) => b.price - a.price),
[products]
);
return <div>...</div>;
}
2. 优先使用 Actions
tsx
// ✅ 推荐:使用 Actions
function TodoForm() {
const [state, formAction] = useActionState(addTodo, {});
return <form action={formAction}>...</form>;
}
// ❌ 不推荐:手动管理
function TodoForm() {
const [isPending, setIsPending] = useState(false);
// 大量样板代码...
}
3. 合理使用服务端组件
tsx
// ✅ 推荐:数据获取在服务端
async function ProductPage({ id }) {
const product = await fetchProduct(id);
return <ProductDetail product={product} />;
}
// ❌ 不推荐:在客户端获取
'use client';
function ProductPage({ id }) {
const [product, setProduct] = useState(null);
useEffect(() => {
fetchProduct(id).then(setProduct);
}, [id]);
return <ProductDetail product={product} />;
}
4. 使用 useOptimistic 提升体验
tsx
// ✅ 推荐:乐观更新
function LikeButton({ postId, likes }) {
const [optimisticLikes, addLike] = useOptimistic(
likes,
(current, amount) => current + amount
);
return (
<button onClick={() => {
addLike(1);
updateLikes(postId);
}}>
❤️ {optimisticLikes}
</button>
);
}
注意事项
1. 编译器限制
React Compiler 在某些情况下可能无法优化:
tsx
// ⚠️ 编译器可能无法完全优化
function Component() {
// 动态生成的函数
const handler = new Function('alert("hello")');
// 使用 eval
eval('console.log("test")');
}
2. 服务端组件限制
tsx
// ❌ 服务端组件不能使用
// - useState
// - useEffect
// - 浏览器 API
// - 事件处理
// ✅ 正确做法:拆分为服务端和客户端组件
// 服务端组件
async function DataWrapper() {
const data = await fetchData();
return <InteractiveComponent data={data} />;
}
// 客户端组件
'use client';
function InteractiveComponent({ data }) {
const [selected, setSelected] = useState(null);
return <div onClick={() => setSelected(data)}>...</div>;
}
3. 向后兼容性
大多数 React 18 代码可以直接运行在 React 19,但需要注意:
- 移除了部分已废弃的 API
- 某些边缘情况行为可能改变
- 建议查看官方迁移指南
总结
React 19 的核心价值
- ✨ 自动优化 - 编译器自动处理性能优化
- 🚀 开发效率 - Actions 和新 Hooks 大幅简化代码
- ⚡ 更快的应用 - 服务端组件和编译器优化
- 📱 更好的用户体验 - useOptimistic 等新特性
- 🎯 内置最佳实践 - SEO、表单、异步处理开箱即用
升级建议
| 项目阶段 | 建议 |
|---|---|
| 新项目 | ✅ 立即使用 React 19 |
| 小型项目 | ✅ 尽快升级 |
| 中型项目 | ⚠️ 测试后逐步升级 |
| 大型项目 | ⚠️ 制定详细迁移计划 |
React 19 不仅是一次版本更新,更是 React 开发范式的革新。它让我们写更少的代码,构建更快的应用,提供更好的用户体验。
现在就开始你的 React 19 之旅吧! 🚀
参考资源:
最后更新: 2025-12-09
欢迎访问我的个人网站: hixiaohezi.com
