一文搞懂 React 19 新特性
以下是 React 19 的主要新特性总结及示例说明,基于当前可用信息整理。需要注意的是,React 19 的某些特性在发布时可能有所调整,请务必以最终的官方文档为准。
🔥 React 19 新特性概览
| 特性类别 | 核心内容 | 主要优势 |
|---|---|---|
| Actions & 异步处理 | useActionState, useFormStatus, useOptimistic | 简化异步状态(pending, error)管理,支持乐观更新 |
| 新 Hooks | use() Hook | 在渲染中直接读取 Promise 或 Context 的值 |
| 服务器组件 | Server Components (稳定版) | 服务端直接渲染,减小客户端包体积,提升首屏加载和SEO |
| 资源与元数据管理 | 原生 <title>, <meta> 支持;preload, preinit API | 更好SEO,优化资源加载优先级与性能 |
| 开发体验优化 | Ref 可作为 prop 传递;Context 提供者语法简化 | 减少 forwardRef 使用,减少样板代码 |
| 性能优化 | React Compiler (实验性);自动批处理增强 | 自动优化渲染,减少手动记忆化(如 useMemo)需求 |
1. Actions 与异步操作管理
Actions 是 React 19 的核心概念,旨在极大地简化表单提交、数据变更等异步操作的处理。
🤔 示例:useActionState处理表单提交
import { useActionState } from 'react';
// 一个模拟的异步 API 调用
async function updateName(formData) {
const name = formData.get('name');
if (!name) {
return 'Name is required';
}
// 模拟网络请求
await new Promise(resolve => setTimeout(resolve, 1000));
return null; // 表示成功
}
function NameForm() {
// useActionState 接收一个异步函数和初始状态
// 返回 [错误状态, 提交动作, 是否进行中]
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData);
return error;
},
null // 初始状态为 null
);
return (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>
{isPending ? 'Updating...' : 'Update'}
</button>
{error && <p style={{color: 'red'}}>{error}</p>}
</form>
);
}
说明:useActionState 自动管理了提交的 pending 状态和错误状态,你无需手动设置 isLoading 或 error 状态变量。
✨ 示例:useOptimistic实现乐观更新
乐观更新是指在服务器确认操作成功之前,就先在 UI 上显示预期的结果,以提升用户体验。
import { useOptimistic, useState } from 'react';
function LikeButton({ initialLikes }) {
const [likes, setLikes] = useState(initialLikes);
// useOptimistic 接收当前状态
// 返回一个乐观状态和一个更新函数
const [optimisticLikes, setOptimisticLikes] = useOptimistic(
likes,
(currentState, amount) => currentState + amount
);
const handleClick = async () => {
// 立即乐观地更新 UI
setOptimisticLikes(1);
// 模拟向服务器发送请求
await likePost();
// 实际更新状态
setLikes((prev) => prev + 1);
};
return (
<button onClick={handleClick}>
{optimisticLikes} Likes {/* 按钮上的数字会立即增加 */}
</button>
);
}
🔗 示例:useFormStatus在子组件中获取表单状态
在 React 19 中,useFormStatus 是一个专门用于获取表单提交状态信息的 Hook。它旨在简化与表单操作相关的状态管理,尤其适用于需要根据表单提交状态更新UI的场景。
以下是对 useFormStatus 返回的状态对象中各个参数的详细说明。
| 属性 | 类型 | 描述 |
|---|---|---|
| pending | Boolean | 表示其所属的父级 <form> 是否正在提交中。 |
| data | FormData | null | 包含父级 <form> 正在提交的数据。 |
| method | String | 表示父级 <form> 提交所使用的 HTTP 方法。 |
| action | Function | null | 指向传递给父级 <form> 的 action 属性的函数引用。 |
深入理解参数
🔄pending
这是最常用的属性。当表单正在提交时(例如,action 函数正在执行),pending 为 true;提交完成后,变为 false。
- 主要用途:提供用户反馈,例如在提交期间禁用提交按钮以防止重复提交,显示加载指示器,或暂时禁用整个表单的输入。
📦data
此属性提供了正在提交的表单数据对象(FormData)。你可以通过 data.get('fieldName') 来访问特定字段的值。这在需要根据提交的数据内容来调整子组件UI时非常有用。如果表单未被提交,其值为 null。
🌐method
它反映了表单的 method 属性,通常是 'get' 或 'post'。默认情况下,如果未指定 method,其值可能为 'get'。这个信息可以用于在UI上显示更具描述性的状态,例如 “正在创建…” 或 “正在获取…”。
⚡action
此属性提供了对传递给父级 <form> 的 action 属性的那个函数的引用。如果 action 属性不是一个函数(例如一个URL字符串),或者未提供,那么此值为 null。
代码示例
下面的例子展示了如何综合使用这些属性,提供一个包含加载状态和提交数据预览的复杂反馈。
import { useFormStatus } from 'react-dom';
// 这是一个位于 <form> 内部的子组件
function AdvancedFormStatus() {
const { pending, data, method } = useFormStatus();
return (
<div style={{ opacity: pending ? 0.7 : 1 }}>
{/* 显示提交状态 */}
<button type="submit" disabled={pending}>
{pending ? (method === 'POST' ? '提交中...' : '获取中...') : '提交'}
</button>
{/* 如果正在提交,显示正在提交的数据预览 */}
{pending && data && (
<div>
<p>正在提交的数据:</p>
<ul>
{/* 遍历显示所有表单项 */}
{Array.from(data.entries()).map(([key, value], index) => (
<li key={index}>{key}: {value.toString()}</li>
))}
</ul>
</div>
)}
</div>
);
}
// 在父组件中使用
function MyForm() {
async function handleSubmit(formData) {
// 你的表单提交逻辑
console.log('提交数据:', Object.fromEntries(formData));
// 模拟网络请求
await new Promise(resolve => setTimeout(resolve, 2000));
}
return (
<form action={handleSubmit}>
<input type="text" name="username" placeholder="用户名" />
<input type="email" name="email" placeholder="邮箱" />
<AdvancedFormStatus />
</form>
);
}
⚠️ 重要使用须知
- 组件层级:useFormStatus 必须在其所属的 <form> 元素的子组件内部被调用。它通过React的上下文系统工作,只能访问最近的父表单的状态。将它和表单写在同一个组件层级是无效的。
- 依赖 action 属性:它仅能返回使用 action 属性(特别是异步函数)的表单的状态信息。如果你的提交逻辑主要在 onSubmit 事件中处理,并且调用了 e.preventDefault() 阻止了默认行为,那么 action 函数将不会执行,useFormStatus 也就无法正确捕获状态。
希望这份详细的说明能帮助你更好地理解和使用 useFormStatus Hook。
说明:useFormStatus 使得按钮这类子组件可以轻松获取到其所属表单的提交状态,无需通过 props 层层传递。
2.useHook
use Hook 允许你在组件渲染过程中有条件地读取资源(如 Promise 或 Context)的值。
🤔 示例:使用use加载异步数据
import { use, Suspense } from 'react';
// 一个模拟的数据获取函数,返回 Promise
function fetchComments() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(['Great post!', 'Thanks for sharing.']);
}, 1000);
});
}
function Comments({ commentsPromise }) {
// 使用 use Hook 来解析 Promise
// 需要与 Suspense 配合使用以显示加载状态
const comments = use(commentsPromise);
return comments.map((comment, index) => <p key={index}>{comment}</p>);
}
function BlogPost() {
// 将 Promise 作为 prop 传递给 Comments 组件
return (
<div>
<h1>My Blog Post</h1>
<Suspense fallback={<div>Loading comments...</div>}>
<Comments commentsPromise={fetchComments()} />
</Suspense>
</div>
);
}
说明:use Hook 为在组件内部处理异步依赖提供了更符合 React 范式的方式,通常需要与 Suspense 结合使用。
3. 服务器组件 (Server Components)
React 19 中,服务器组件已达到稳定状态。服务器组件默认在服务端执行,允许你将数据获取和渲染逻辑放在服务端,仅将渲染出的 HTML 发送到客户端,从而减少客户端的 JavaScript 包大小,提升首屏加载性能。
🤔 示例:服务端组件与客户端组件协同工作
// ProductDetails.server.js - 服务端组件
// 服务端组件可以是异步的,直接访问后端资源
async function ProductDetails({ productId }) {
// 在服务端直接获取数据
const product = await db.products.get(productId);
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
{/* 在服务端组件内部嵌套客户端交互组件 */}
<AddToCartButton product={product} />
</div>
);
}
// AddToCartButton.client.js - 客户端组件
// 使用 "use client" 指令标记
'use client';
import { useOptimistic } from 'react';
function AddToCartButton({ product }) {
const [cart, setCart] = useOptimistic([]);
const addToCart = async () => {
// ... 客户端交互逻辑
};
return <button onClick={addToCart}>Add to Cart</button>;
}
说明:通过 'use client' 指令,可以明确划分服务端和客户端组件。服务端组件负责数据和静态内容,客户端组件负责交互,二者可以无缝嵌套。
4. 文档元数据管理
现在,你可以直接在组件内使用 <title>, <meta>, <link> 等标签,React 会自动将它们提升到文档的 <head> 部分。
🤔 示例:在组件中设置页面标题和 Meta 信息
function BlogPost({ post }) {
return (
<article>
{/* 这些标签会被自动提升到 <head> 中 */}
<title>{post.title}</title>
<meta name="description" content={post.excerpt} />
<meta name="keywords" content={post.keywords} />
<link rel="canonical" href={post.canonicalUrl} />
{/* 页面内容 */}
<h1>{post.title}</h1>
<div>{post.content}</div>
</article>
);
}
说明:这一特性简化了 SEO 管理,无需再依赖如 react-helmet 等第三方库,并且在服务端渲染 (SSR) 和客户端渲染 (CSR) 下都能正常工作。
5. 资源预加载
新的资源预加载 API(如 preload 和 preinit)允许你更精细地控制关键资源(如字体、脚本)的加载时机,优化页面加载性能。
🤔 示例:预加载关键资源
import { preload, preinit } from 'react-dom';
function ProductPage() {
// 预加载重要字体,避免页面渲染时的字体闪烁
preload('/fonts/main-font.woff2', { as: 'font', type: 'font/woff2' });
// 预初始化关键脚本,加快其执行速度
preinit('/js/critical-checkout.js', { as: 'script' });
return (
<div>
{/* 页面内容 */}
</div>
);
}
6. 开发体验优化
Ref 作为 Prop 传递
函数组件现在可以直接接受 ref 作为 prop,无需使用 forwardRef 进行包裹。
// React 19 之前:需要 forwardRef
const MyInput = React.forwardRef((props, ref) => {
return <input {...props} ref={ref} />;
});
// React 19:直接作为 prop 使用
function MyInput({ ref, ...props }) {
return <input {...props} ref={ref} />;
}
function App() {
const inputRef = useRef(null);
return <MyInput ref={inputRef} />;
}
Context 提供者语法简化
// 之前 <ThemeContext.Provider value="dark"> <Children /> </ThemeContext.Provider> // React 19 简化语法 <ThemeContext value="dark"> <Children /> </ThemeContext>
7. 性能优化:React Compiler (实验性)
React 19 引入了实验性的 React Compiler。它能够在构建时自动优化你的组件,例如自动进行记忆化(类似于 useMemo, useCallback),从而减少不必要的重新渲染,可能带来显著的性能提升。
// 开发者编写的代码
function MyComponent({ data }) {
const transformedData = expensiveTransformation(data);
return <div>{transformedData}</div>;
}
// React Compiler 可能会在背后自动优化,类似于:
function MyComponent_optimized({ data }) {
const transformedData = useMemo(() => expensiveTransformation(data), [data]);
return <div>{transformedData}</div>;
}
注意:此功能目前仍是实验性的,可能需要手动启用。
到此这篇关于一文搞懂 React 19 新特性的文章就介绍到这了,更多相关React 19 新特性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
react页面中存在多个input时巧妙设置value属性方式
这篇文章主要介绍了react页面中存在多个input时巧妙设置value属性方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2023-05-05
react学习每天一个hooks useWhyDidYouUpdate
这篇文章主要为大家介绍了react学习每天一个hooks useWhyDidYouUpdate使用示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-04-04


最新评论