一、React 19 核心新特性详解
Actions(动作系统)🎯
是什么: React 19 的核心概念,用于统一管理异步操作和状态
包含的新Hook:
useActionState- 处理表单提交状态,自动跟踪并更新待处理状态useFormStatus- 获取表单状态useOptimistic- 乐观更新
核心思想: 让 React 自动管理你的异步状态
新增 Hook 详解
2.1 useActionState
用途: 替代 useState + useEffect 处理表单提交
scss
// 🔥 React 19 新写法
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateUser(formData);
return error;
},
null
);
// 🆚 React 18 旧写法对比
const [error, setError] = useState(null);
const [isPending, setIsPending] = useState(false);
const handleSubmit = async (formData) => {
setIsPending(true);
try {
const err = await updateUser(formData);
setError(err);
} finally {
setIsPending(false);
}
};
优势:
- ✅ 代码减少 50%
- ✅ 状态自动管理
- ✅ 错误处理更简洁
2.2 useFormStatus
用途: 在子组件中直接获取父表单状态
javascript
// 🔥 React 19 新写法
// 父组件完全不需要传递状态
function SubmitButton() {
const { pending, data } = useFormStatus();
return <button disabled={pending}>提交{pending && '中...'}</button>;
}
// 🆚 React 18 旧写法对比
// 父组件必须传递 isSubmitting 状态
function SubmitButton({ isSubmitting }) {
return <button disabled={isSubmitting}>提交{isSubmitting && '中...'}</button>;
}
优势:
- ✅ 组件解耦
- ✅ 减少 props 传递
- ✅ 代码更简洁
2.3 useOptimistic
用途: 实现乐观更新,提升用户体验
scss
// 🔥 React 19 新写法
const [messages, addOptimistic] = useOptimistic(
messages,
(state, newMessage) => [ { text: newMessage, sending: true }, ...state ]
);
// 发送消息时立即显示,失败自动回退
// 🆚 React 18 旧写法对比
const [messages, setMessages] = useState([]);
const [tempMessage, setTempMessage] = useState(null);
const sendMessage = async (text) => {
setTempMessage({ text, sending: true });
try {
await api.send(text);
setMessages([{ text }, ...messages]);
} catch {
// 手动回退
} finally {
setTempMessage(null);
}
};
优势:
- ✅ 用户体验更好
- ✅ 代码逻辑简化
- ✅ 自动错误处理
2.4 use
用途: 读取 Promise 或 Context,支持条件调用
php
// 用途1:处理异步 Promise(配合 Suspense)
const data = use(dataPromise);
// 用途2:读取 Context(替代 useContext)
const theme = use(ThemeContext);
// ✅ React 19 新用法
支持条件调用
javascript
// 🔥 React 19 新写法
function Button({ show }) {
if (show) {
const theme = use(ThemeContext); // ✅ 可以在条件语句中调用
return <button className={`btn-${theme}`}>点击</button>;
}
return null;
}
// 🆚 React 18 旧写法对比
function Button({ show }) {
const theme = useContext(ThemeContext); // ❌ 必须在顶层调用
if (!show) return null;
return <button className={`btn-${theme}`}>点击</button>;
}
处理异步场景:use 与 Suspense 深度集成,可以更自然地处理异步数据的加载状态
javascript
// 🔥 React 19 新写法
// 使用 React 19 的方式:无需手动管理 loading 状态和 useEffect
// use 与 Suspense 深度集成,可以更自然地处理异步数据的加载状态。
// 父组件:提供 Promise 和 Suspense
<Suspense fallback={<Loader />}>
<Child dataPromise={dataPromise} />
</Suspense>
// 子组件:使用 use 消费数据
const Child = ({ dataPromise }) => {
const data = use(dataPromise);
return <div>{data}</div>;
};
// 🆚 React 18 旧写法对比
// 场景:需要获取异步数据
function useFetch() {
const [content, update] = useState({ value: '' })
const [loading, setLoading] = useState(true)
// 2、useFetch 函数中利用 useEffect 解析 Promise 结果,useState 管理状态,并将所有结果返回给组件
useEffect(() => {
api().then(res => {
setLoading(false)
update(res)
})
}, [])
return [content, loading]
}
function App() {
// 1、封装 useFetch 函数获取异步结果
const { content, loading } = useFetch()
// 3、使用状态
if (loading) {
return <Skeleton />
}
// 4、使用返回值
return <Message message={content.value} />
}
优势:
- ✅ 支持条件调用
- ✅ 更好的性能优化
- ✅ 与 Suspense 深度集成
语法简化特性
3.1 Context 简写
javascript
// 🔥 React 19 新写法
<ThemeContext value="dark">
<App />
</ThemeContext>
// 🆚 React 18 旧写法对比
<ThemeContext.Provider value="dark">
<App />
</ThemeContext.Provider>
3.2 Ref 作为普通 Prop
javascript
// 🔥 React 19 新写法
function MyInput({ ref, ...props }) {
return <input ref={ref} {...props} />;
}
// 不再需要 forwardRef!
// 🆚 React 18 旧写法对比
const MyInput = forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
3.3 Ref 清理函数
csharp
// 🔥 React 19 新特性
<input
ref={(ref) => {
// 初始化 ref
return () => {
// 组件卸载时自动清理
ref.current = null;
};
}}
/>
性能优化特性
4.1 React 编译器
特性
React 19 引入了全新的 React 编译器,它是一个自动记忆编译器,可以在构建阶段分析你的代码并自动应用优化。
主要功能:
- ✅ 自动记忆化:自动为昂贵的计算和函数添加
useMemo和useCallback - ✅ 智能重新渲染:分析状态依赖,决定何时更新组件
- ✅ 静态分析:在编译时识别可优化的代码模式
工作原理:
javascript
// 你写的代码 👇
function ProductList({ products, filter }) {
const filtered = products.filter(p => p.category === filter);
const sorted = filtered.sort((a, b) => a.price - b.price);
const handleBuy = (id) => {
addToCart(id);
};
return (
<div>
{sorted.map(product => (
<Product key={product.id} product={product} onBuy={handleBuy} />
))}
</div>
);
}
// 编译器自动优化为 👇
function ProductList({ products, filter }) {
const filtered = useMemo(() =>
products.filter(p => p.category === filter),
[products, filter]
);
const sorted = useMemo(() =>
filtered.sort((a, b) => a.price - b.price),
[filtered]
);
const handleBuy = useCallback((id) => {
addToCart(id);
}, []);
return (
<div>
{sorted.map(product => (
<Product key={product.id} product={product} onBuy={handleBuy} />
))}
</div>
);
}
🔧 以后还需要手动使用 useMemo 和 useCallback 吗?
✅ 大部分情况下不需要
可以交给编译器的情况
javascript
// ✅ 这些场景编译器都能自动优化,不需要手动写:
// 1. 纯计算
const totalPrice = cartItems.reduce((sum, item) => sum + item.price, 0);
// 2. 组件内定义的函数
const handleClick = () => {
console.log('Clicked');
};
// 3. 数组/对象转换
const activeUsers = users.filter(user => user.isActive);
// 4. 派生状态
const discountedPrice = price * (1 - discount);
⚠️ 特殊情况仍然需要手动优化
| 场景 | 原因 | 示例 |
|---|---|---|
| 跨组件传递 | 编译器无法分析子组件的实现 | 编译器无法分析子组件的实现 |
| Effect 依赖 | 需要稳定的函数引用 | useEffect(() => {...}, [fetchData]) |
| 第三方库集成 | 库要求稳定引用 | useForm({ onSubmit: handleSubmit }) |
| Ref 回调 | 需要稳定的回调函数 | |
| 动态依赖 | 依赖外部传入的函数 | items.filter(externalFilterFn) |
javascript
// ⚠️ 仍然需要手动优化:
// 1. 传递给 React.memo 子组件
const MemoizedChild = React.memo(Child);
function Parent() {
// ✅ 需要手动 useCallback
const handleClick = useCallback(() => {
console.log('Child clicked');
}, []);
return <MemoizedChild onClick={handleClick} />;
}
// 2. Effect 依赖
function DataFetcher({ url }) {
// ✅ 需要手动 useCallback
const fetchData = useCallback(async () => {
const response = await fetch(url);
return response.json();
}, [url]);
useEffect(() => {
fetchData();
}, [fetchData]); // 需要稳定的引用
return <div>Loading...</div>;
}
4.2 并行 API 增强
useTransition- 标记非紧急更新useDeferredValue- 延迟更新值
useTransition - 标记非紧急更新
特性: 用于将某些状态更新标记为"非紧急",让 React 优先处理更重要的 UI 更新
startTransition可以标记一个或多个set方法,调低更新的优先级。
isPending表示是否还有未完成UI更新的任务,我们可以利用这个状态来判断请求是否正在发生
scss
// 基本用法
const [isPending, startTransition] = useTransition();
// 示例:搜索时保持输入响应
function SearchBox() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();
const handleSearch = (searchText) => {
// 1️⃣ 紧急更新:立即更新输入框
setQuery(searchText);
// 2️⃣ 非紧急更新:搜索结果可以稍后更新
startTransition(() => {
const newResults = searchData(searchText); // 耗时操作
setResults(newResults);
});
};
return (
<div>
<input
value={query}
onChange={(e) => handleSearch(e.target.value)}
/>
{/* 显示加载状态 */}
{isPending && <div>搜索中...</div>}
<SearchResults results={results} />
</div>
);
}
优势:
- ✅ 保持UI响应性:用户输入不被阻塞
- ✅ 智能加载状态:自动提供
isPending状态 - ✅ 批量更新:可以标记多个状态更新
适用场景:
- 搜索框实时搜索
- 标签页切换
- 大型列表筛选
- 复杂表单验证
useDeferredValue - 延迟更新值
特性: 延迟一个值的更新,先使用旧值渲染,等主线程空闲时再更新。
javascript
// 基本用法
const deferredValue = useDeferredValue(value);
// 示例:图表数据延迟更新
function DataDashboard({ realTimeData }) {
// 立即响应用户交互的部分
const [filter, setFilter] = useState('daily');
// 延迟渲染的复杂图表部分
const deferredData = useDeferredValue(realTimeData);
return (
<div>
{/* 1️⃣ 紧急部分:筛选器立即响应 */}
<FilterControls
value={filter}
onChange={setFilter} // 立即更新
/>
{/* 2️⃣ 非紧急部分:图表可以延迟渲染 */}
<ComplexChart
data={deferredData} // 使用延迟值
filter={filter}
/>
{/* 显示延迟状态 */}
{deferredData !== realTimeData && (
<div>更新数据中...</div>
)}
</div>
);
}
优势:
- ✅ 渐进式更新:先显示内容,再优化内容
- ✅ 防抖动内置:避免频繁重渲染
- ✅ 简单易用:一行代码实现延迟更新
适用场景:
- 实时数据仪表板
- 实时聊天消息流
- 大型数据集渲染
- 复杂可视化图表
📊 两者对比:何时用哪个?
useTransition= "这个更新不重要,可以先做其他的"useDeferredValue= "这个值变化太快,先用旧值,慢慢更新"
| 特性 | useTransition | useDeferredValue |
|---|---|---|
| 控制对象 | 状态更新操作 | 状态值本身 |
| 使用方式 | 包裹 setState 调用 | 包裹状态值 |
| 适用场景 | 主动触发的更新 | 被动接收的更新 |
| 典型用例 | 用户交互后的复杂计算 | 接收频繁更新的外部数据 |
🎯 组合使用示例
scss
// 组合使用示例
function OptimizedApp() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();
const deferredQuery = useDeferredValue(query);
// 搜索建议快速响应
useEffect(() => {
showQuickSuggestions(query);
}, [query]);
// 搜索结果延迟计算
useEffect(() => {
startTransition(() => {
const newResults = search(deferredQuery);
setResults(newResults);
});
}, [deferredQuery]);
return (
<div>
<SearchInput
value={query}
onChange={setQuery}
/>
{isPending && <Spinner />}
<SearchResults results={results} />
</div>
);
}
开发体验提升
5.1 文档元数据原生支持
现在可以直接在组件里写 <title>、<meta>、<link> 标签,React 会自动把它们放到页面的 <head> 里。
javascript
// 🔥 React 19 新写法
function BlogPost({ post }) {
return (
<article>
<title>{post.title}</title>
<meta name="description" content={post.excerpt} />
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
// 自动将 title、meta 提升到 <head>
// 🆚 React 18 旧写法对比
import { Helmet } from 'react-helmet';
function BlogPost({ post }) {
return (
<>
// 需要借助第三方库,进行插入
<Helmet>
<title>{post.title}</title>
<meta name="description" content={post.excerpt} />
</Helmet>
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
</>
);
}
优势:
- ✅ 开发更简单
- ✅ SEO 更友好
- ✅ 性能更优秀
5.2 样式表优先级管理
现在可以用 precedence 属性精确控制样式表的加载顺序,确保正确的样式覆盖。
ini
// 控制样式表加载顺序
<link rel="stylesheet" href="base.css" precedence="default" />
<link rel="stylesheet" href="theme.css" precedence="high" />
5.3 资源预加载
React 19 包含了一些新的api,用于加载和预加载浏览器资源,使得构建不受资源加载效率影响的优秀体验变得尽可能容易。
csharp
import { preload, prefetchDNS } from 'react-dom';
// 预加载关键资源
preload('/critical-font.woff2', { as: 'font' });
prefetchDNS('https://api.example.com');
6. 移除的特性与破坏性变化
以下仅罗列常用的 api,具体请查看:breaking-changes
6.1 不再支持的功能
javascript
// ❌ React 19 中已移除
import PropTypes from 'prop-types'; // 不再需要
import { createFactory } from 'react'; // 已移除
import ShallowRenderer from 'react-test-renderer/shallow'; // 用 import ShallowRenderer from 'react-shallow-renderer'; 替代
// ❌ 这些API已移除
ReactDOM.render(<App />, container); // 用 createRoot 替代
ReactDOM.hydrate(<App />, container); // 用 hydrateRoot 替代
ReactDOM.findDOMNode(); // 用 useRef 引用去拿 ref?.current
6.2 严格模式的变化
javascript
// ✅ React 19 中更严格的检查
<React.StrictMode>
<App /> {/* 会检查废弃API使用 */}
</React.StrictMode>
7. TypeScript 改进
7.1 更好的类型推断
php
// ✅ useActionState 的完整类型
const [error, action, pending] = useActionState<
string | null, // State 类型
FormData, // FormData 类型
string | null // 返回值类型
>(
async (prevState: string | null, formData: FormData) => {
// 自动推断类型
return 'error message' as string | null;
},
null // initialState
);
7.2 use Hook 类型支持
ini
const data = use<Promise<Data>>(dataPromise); // 明确的泛型类型
const context = use<ThemeType>(ThemeContext); // Context 类型推断
二、前后对比总结表
| 特性 | React 18 (旧) | React 19 (新) | 优势 |
|---|---|---|---|
| 表单状态管理 | 手动 useState + useEffect | useActionState 自动管理 | 更简洁,自动错误处理 |
| 表单状态传递 | props 层层传递 | useFormStatus 直接获取 | 组件解耦,减少 props |
| 乐观更新 | 手动实现复杂逻辑 | useOptimistic 自动处理 | 更好的用户体验 |
| Context 读取 | 必须在顶层调用 | use() 支持条件调用 | 更好的性能优化 |
| Context 提供 | .Provider 包装 | 直接使用 Context | 语法更简洁 |
| Ref 传递 | forwardRef 包装 | ref 作为普通 prop | 符合直觉 |
| 文档 元数据 | react-helmet 库 | 原生支持 | 更好的 SSR 支持 |
| 性能优化 | 手动 useMemo/useCallback | 编译器自动优化 | 开发更简单 |