本文最后更新于:2025-11-25T14:35:03+08:00
forwardRef 的弃用
传统的 forwardRef 用法
在 React 19 之前,forwardRef 是一个高阶函数,用于让子组件能够接收并转发父组件传递过来的 ref,从而允许父组件直接访问子组件中的 DOM 元素或组件实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import React, { useRef, forwardRef } from 'react';
const ChildComponent = forwardRef((props, ref) => { return ( <input ref={ref} type="text" placeholder="请输入内容" /> ); });
const ParentComponent = () => { const inputRef = useRef(null);
const focusInput = () => { inputRef.current.focus(); };
return ( <div> <ChildComponent ref={inputRef} /> <button onClick={focusInput}>聚焦输入框</button> </div> ); };
export default ParentComponent;
|

React 19 的改进
在 React 19 中,官网显示 forwardRef 已被弃用。现在我们无需再用 forwardRef 来封装子组件,可以直接在子组件的 props 中接收 ref。

React 19 的新写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import React, { useRef } from 'react';
function ChildComponent({ ref, ...props }) { return ( <input ref={ref} type="text" placeholder="请输入内容" {...props} /> ); }
function ChildComponent(props) { return ( <input ref={props.ref} type="text" placeholder="请输入内容" /> ); }
const ParentComponent = () => { const inputRef = useRef(null);
const focusInput = () => { inputRef.current.focus(); };
return ( <div> <ChildComponent ref={inputRef} /> <button onClick={focusInput}>聚焦输入框</button> </div> ); };
|
更复杂的示例:配合 useImperativeHandle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import React, { useRef, useImperativeHandle } from 'react';
function CustomInput({ ref, label }) { const inputRef = useRef(null);
useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); }, clear: () => { inputRef.current.value = ''; }, getValue: () => { return inputRef.current.value; } }));
return ( <div> <label>{label}</label> <input ref={inputRef} type="text" /> </div> ); }
function App() { const customInputRef = useRef(null);
const handleSubmit = () => { const value = customInputRef.current.getValue(); console.log('输入值:', value); customInputRef.current.clear(); };
return ( <div> <CustomInput ref={customInputRef} label="用户名:" /> <button onClick={handleSubmit}>提交</button> </div> ); }
|
迁移指南
如果你的项目需要从旧版本迁移到 React 19:
- 简单组件:直接移除
forwardRef 包装,在 props 中接收 ref
- 复杂组件:保持
useImperativeHandle 的使用,只需移除 forwardRef
- 类型定义(TypeScript):更新类型定义以包含 ref
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import { forwardRef, ForwardedRef } from 'react';
interface Props { label: string; }
const Input = forwardRef<HTMLInputElement, Props>((props, ref) => { return <input ref={ref} {...props} />; });
interface Props { label: string; ref?: React.Ref<HTMLInputElement>; }
function Input({ ref, label, ...props }: Props) { return <input ref={ref} {...props} />; }
|
新 API:use

use 是 React 19 引入的一个全新 API,它可以让你读取类似于 Promise 或 Context 的资源的值。这是 React 首个可以在条件语句和循环中调用的 Hook。
核心特性
- 可以在条件语句中使用(突破了 Hooks 规则的限制)
- 支持读取 Promise
- 支持读取 Context
- 通常搭配
Suspense 和错误边界使用
使用场景一:读取 Context
use 可以替代 useContext,并且更加灵活,可以在条件语句中使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import { createContext, use } from 'react';
const ThemeContext = createContext(null);
export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ); }
function Form() { return ( <Panel title="Welcome"> <Button show={true}>Sign up</Button> <Button show={false}>Log in</Button> </Panel> ); }
function Panel({ title, children }) { const theme = use(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ); }
function Button({ show, children }) { if (show) { const theme = use(ThemeContext); const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); } return false; }
|
对比 useContext:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function Button({ show, children }) { if (show) { const theme = useContext(ThemeContext); return <button>{children}</button>; } }
function Button({ show, children }) { if (show) { const theme = use(ThemeContext); return <button>{children}</button>; } }
|
使用场景二:读取 Promise(数据获取)
use 最强大的功能是可以直接读取 Promise,配合 Suspense 实现优雅的异步数据加载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import { use, Suspense } from 'react';
function fetchUser(userId) { return fetch(`/api/users/${userId}`) .then(res => res.json()); }
function UserProfile({ userPromise }) { const user = use(userPromise);
return ( <div> <h2>{user.name}</h2> <p>{user.email}</p> <p>{user.bio}</p> </div> ); }
function App() { const userPromise = fetchUser(1);
return ( <Suspense fallback={<div>加载用户信息...</div>}> <UserProfile userPromise={userPromise} /> </Suspense> ); }
|
使用场景三:配合 Suspense 和 ErrorBoundary
完整的错误处理和加载状态管理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import { use, Suspense } from 'react'; import { ErrorBoundary } from 'react-error-boundary';
function Message({ messagePromise }) { const messageContent = use(messagePromise); return <p>Here is the message: {messageContent}</p>; }
export function MessageContainer({ messagePromise }) { return ( <ErrorBoundary fallback={<p>⚠️ Something went wrong</p>}> <Suspense fallback={<p>⌛ Downloading message...</p>}> <Message messagePromise={messagePromise} /> </Suspense> </ErrorBoundary> ); }
function App() { const messagePromise = fetch('/api/message') .then(res => { if (!res.ok) throw new Error('Failed to fetch'); return res.text(); });
return <MessageContainer messagePromise={messagePromise} />; }
|
高级用法:条件数据获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import { use, Suspense, useState } from 'react';
function UserData({ userId }) { if (!userId) { return <div>请选择一个用户</div>; }
const user = use(fetchUser(userId));
return ( <div> <h2>{user.name}</h2> <p>{user.email}</p> </div> ); }
function App() { const [selectedUserId, setSelectedUserId] = useState(null);
return ( <div> <select onChange={(e) => setSelectedUserId(e.target.value)}> <option value="">选择用户</option> <option value="1">用户 1</option> <option value="2">用户 2</option> </select>
<Suspense fallback={<div>加载中...</div>}> <UserData userId={selectedUserId} /> </Suspense> </div> ); }
|
循环中使用 use
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| function PostList({ postIds }) { return ( <ul> {postIds.map(id => { // 在循环中使用 use const post = use(fetchPost(id)); return ( <li key={id}> <h3>{post.title}</h3> <p>{post.content}</p> </li> ); })} </ul> ); }
function App() { return ( <Suspense fallback={<div>加载文章列表...</div>}> <PostList postIds={[1, 2, 3, 4, 5]} /> </Suspense> ); }
|
use vs useContext vs 传统数据获取
| 特性 |
use |
useContext |
useEffect + useState |
| 可在条件语句中使用 |
✅ |
❌ |
❌ |
| 可在循环中使用 |
✅ |
❌ |
❌ |
| 读取 Promise |
✅ |
❌ |
需要手动处理 |
| 读取 Context |
✅ |
✅ |
❌ |
| 自动 Suspense |
✅ |
❌ |
需要手动实现 |
| 错误处理 |
自动(配合 ErrorBoundary) |
❌ |
需要手动实现 |
注意事项
- Promise 必须是稳定的:不要在组件内部创建 Promise,应该从 props 接收或使用缓存
- 配合 Suspense 使用:读取 Promise 时必须包裹在 Suspense 中
- 错误边界:建议配合 ErrorBoundary 处理错误情况
- SSR 支持:use API 完全支持服务端渲染
React 19 Actions
Actions 是 React 19 引入的一个重要概念,用于处理数据变更操作(如表单提交、API 调用等)。Actions 自动处理加载状态、错误处理和乐观更新。
什么是 Actions
Actions 是异步函数,用于管理数据提交的整个生命周期:
- pending 状态:自动跟踪异步操作的进行状态
- 错误处理:自动捕获和处理错误
- 乐观更新:在请求完成前先更新 UI
- 自动重置:表单自动重置
useActionState
useActionState 是用于管理 Action 状态的新 Hook。
基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import { useActionState } from 'react';
async function updateName(previousState, formData) { const name = formData.get('name'); try { await fetch('/api/update-name', { method: 'POST', body: JSON.stringify({ name }) }); return { success: true, message: '更新成功!' }; } catch (error) { return { success: false, message: '更新失败' }; } }
function UpdateNameForm() { const [state, submitAction, isPending] = useActionState(updateName, { success: null, message: '' });
return ( <form action={submitAction}> <input type="text" name="name" required /> <button type="submit" disabled={isPending}> {isPending ? '提交中...' : '提交'} </button> {state.message && ( <p style={{ color: state.success ? 'green' : 'red' }}> {state.message} </p> )} </form> ); }
|
完整示例:用户注册表单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| import { useActionState } from 'react';
async function registerUser(previousState, formData) { const username = formData.get('username'); const email = formData.get('email'); const password = formData.get('password');
if (password.length < 6) { return { success: false, errors: { password: '密码至少需要6个字符' } }; }
try { const response = await fetch('/api/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, email, password }) });
if (!response.ok) { const error = await response.json(); return { success: false, errors: error }; }
const user = await response.json(); return { success: true, user }; } catch (error) { return { success: false, errors: { general: '注册失败,请稍后重试' } }; } }
function RegistrationForm() { const [state, submitAction, isPending] = useActionState(registerUser, { success: null, errors: {} });
return ( <form action={submitAction}> <div> <label htmlFor="username">用户名:</label> <input id="username" name="username" type="text" required disabled={isPending} /> </div>
<div> <label htmlFor="email">邮箱:</label> <input id="email" name="email" type="email" required disabled={isPending} /> {state.errors?.email && ( <span className="error">{state.errors.email}</span> )} </div>
<div> <label htmlFor="password">密码:</label> <input id="password" name="password" type="password" required disabled={isPending} /> {state.errors?.password && ( <span className="error">{state.errors.password}</span> )} </div>
<button type="submit" disabled={isPending}> {isPending ? '注册中...' : '注册'} </button>
{state.errors?.general && ( <p className="error">{state.errors.general}</p> )}
{state.success && ( <p className="success">注册成功!欢迎 {state.user.username}</p> )} </form> ); }
|
useActionState 参数详解
1
| const [state, action, isPending] = useActionState(fn, initialState, permalink?)
|
- fn: Action 函数,接收
(previousState, formData) 参数
- initialState: 初始状态
- permalink(可选): 用于渐进增强的 URL
- 返回值:
state: 当前状态
action: 可以传递给表单的 action 属性
isPending: 布尔值,表示操作是否正在进行
useOptimistic
useOptimistic 用于实现乐观更新,在服务器响应前先更新 UI,提供即时反馈。
基本概念
乐观更新:先假设操作会成功,立即更新 UI,如果失败再回滚。
基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import { useOptimistic, useState } from 'react';
function LikeButton({ postId, initialLikes }) { const [likes, setLikes] = useState(initialLikes); const [optimisticLikes, addOptimisticLike] = useOptimistic( likes, (currentLikes, amount) => currentLikes + amount );
async function handleLike() { addOptimisticLike(1);
try { const response = await fetch(`/api/posts/${postId}/like`, { method: 'POST' }); const data = await response.json(); setLikes(data.likes); } catch (error) { console.error('点赞失败', error); } }
return ( <button onClick={handleLike}> ❤️ {optimisticLikes} 个赞 </button> ); }
|
完整示例:待办事项列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| import { useOptimistic, useState } from 'react';
function TodoList() { const [todos, setTodos] = useState([ { id: 1, text: '学习 React 19', completed: false }, { id: 2, text: '写博客文章', completed: false } ]);
const [optimisticTodos, addOptimisticTodo] = useOptimistic( todos, (currentTodos, newTodo) => { if (newTodo.type === 'add') { return [...currentTodos, newTodo.todo]; } else if (newTodo.type === 'toggle') { return currentTodos.map(todo => todo.id === newTodo.id ? { ...todo, completed: !todo.completed } : todo ); } else if (newTodo.type === 'delete') { return currentTodos.filter(todo => todo.id !== newTodo.id); } return currentTodos; } );
async function addTodo(text) { const newTodo = { id: Date.now(), text, completed: false };
addOptimisticTodo({ type: 'add', todo: newTodo });
try { const response = await fetch('/api/todos', { method: 'POST', body: JSON.stringify(newTodo) }); const savedTodo = await response.json(); setTodos(prev => [...prev, savedTodo]); } catch (error) { console.error('添加失败', error); } }
async function toggleTodo(id) { addOptimisticTodo({ type: 'toggle', id });
try { await fetch(`/api/todos/${id}/toggle`, { method: 'POST' }); setTodos(prev => prev.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo ) ); } catch (error) { console.error('切换失败', error); } }
async function deleteTodo(id) { addOptimisticTodo({ type: 'delete', id });
try { await fetch(`/api/todos/${id}`, { method: 'DELETE' }); setTodos(prev => prev.filter(todo => todo.id !== id)); } catch (error) { console.error('删除失败', error); } }
return ( <div> <h2>待办事项</h2> <ul> {optimisticTodos.map(todo => ( <li key={todo.id} style={{ textDecoration: todo.completed ? 'line-through' : 'none', opacity: todo.id > 1000000000000 ? 0.6 : 1 // 新添加的项稍微透明 }} > <input type="checkbox" checked={todo.completed} onChange={() => toggleTodo(todo.id)} /> {todo.text} <button onClick={() => deleteTodo(todo.id)}>删除</button> </li> ))} </ul> </div> ); }
|
聊天应用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import { useOptimistic, useState } from 'react';
function ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); const [optimisticMessages, addOptimisticMessage] = useOptimistic( messages, (currentMessages, newMessage) => [...currentMessages, newMessage] );
async function sendMessage(text) { const tempMessage = { id: Date.now(), text, sender: 'me', status: 'sending' };
addOptimisticMessage(tempMessage);
try { const response = await fetch(`/api/rooms/${roomId}/messages`, { method: 'POST', body: JSON.stringify({ text }) }); const savedMessage = await response.json(); setMessages(prev => [...prev, savedMessage]); } catch (error) { alert('消息发送失败'); } }
return ( <div> <div className="messages"> {optimisticMessages.map(msg => ( <div key={msg.id} className={`message ${msg.status === 'sending' ? 'pending' : ''}`} > <strong>{msg.sender}:</strong> {msg.text} {msg.status === 'sending' && <span>⏳</span>} </div> ))} </div> <MessageInput onSend={sendMessage} /> </div> ); }
|
useFormStatus 用于获取表单的提交状态,特别适合在表单的子组件中使用。
基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import { useFormStatus } from 'react-dom';
function SubmitButton() { const { pending, data, method, action } = useFormStatus();
return ( <button type="submit" disabled={pending}> {pending ? '提交中...' : '提交'} </button> ); }
function MyForm() { async function handleSubmit(formData) { const name = formData.get('name'); await fetch('/api/submit', { method: 'POST', body: JSON.stringify({ name }) }); }
return ( <form action={handleSubmit}> <input type="text" name="name" /> <SubmitButton /> </form> ); }
|
完整示例:带加载状态的表单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| import { useFormStatus } from 'react-dom'; import { useActionState } from 'react';
function SubmitButton({ children }) { const { pending } = useFormStatus();
return ( <button type="submit" disabled={pending}> {pending ? ( <> <Spinner /> 提交中... </> ) : ( children )} </button> ); }
function FormFields() { const { pending } = useFormStatus();
return ( <> <input type="email" name="email" placeholder="邮箱" disabled={pending} required /> <input type="password" name="password" placeholder="密码" disabled={pending} required /> </> ); }
async function login(previousState, formData) { const email = formData.get('email'); const password = formData.get('password');
try { const response = await fetch('/api/login', { method: 'POST', body: JSON.stringify({ email, password }) });
if (!response.ok) { return { error: '登录失败,请检查邮箱和密码' }; }
return { success: true }; } catch (error) { return { error: '网络错误,请稍后重试' }; } }
function LoginForm() { const [state, action] = useActionState(login, {});
return ( <form action={action}> <FormFields /> <SubmitButton>登录</SubmitButton> {state.error && ( <p className="error">{state.error}</p> )} {state.success && ( <p className="success">登录成功!</p> )} </form> ); }
|
高级示例:多步骤表单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| import { useFormStatus } from 'react-dom'; import { useState } from 'react';
function StepIndicator({ currentStep, totalSteps }) { const { pending } = useFormStatus();
return ( <div className="steps"> {Array.from({ length: totalSteps }, (_, i) => ( <div key={i} className={`step ${i < currentStep ? 'completed' : ''} ${ i === currentStep ? 'active' : '' } ${pending ? 'disabled' : ''}`} > 步骤 {i + 1} </div> ))} </div> ); }
function NavigationButtons({ currentStep, totalSteps, onBack }) { const { pending } = useFormStatus();
return ( <div className="navigation"> {currentStep > 0 && ( <button type="button" onClick={onBack} disabled={pending} > 上一步 </button> )} <button type="submit" disabled={pending}> {pending ? ( '处理中...' ) : currentStep === totalSteps - 1 ? ( '完成' ) : ( '下一步' )} </button> </div> ); }
function MultiStepForm() { const [step, setStep] = useState(0);
async function handleSubmit(formData) { await new Promise(resolve => setTimeout(resolve, 1000)); if (step < 2) { setStep(step + 1); } else { console.log('表单提交完成'); } }
return ( <form action={handleSubmit}> <StepIndicator currentStep={step} totalSteps={3} /> {step === 0 && <Step1Fields />} {step === 1 && <Step2Fields />} {step === 2 && <Step3Fields />} <NavigationButtons currentStep={step} totalSteps={3} onBack={() => setStep(step - 1)} /> </form> ); }
|
1
| const { pending, data, method, action } = useFormStatus();
|
- pending: 布尔值,表示表单是否正在提交
- data: FormData 对象,包含表单数据
- method: 字符串,表单的 method(’get’ 或 ‘post’)
- action: 函数引用,表单的 action
注意事项
- 必须在表单内部使用:
useFormStatus 必须在 <form> 的子组件中调用
- 只能读取父表单状态:不能读取同级或子表单的状态
- 配合 Actions 使用:最佳实践是配合
useActionState 使用
其他 React 19 新特性
1. 文档元数据支持
React 19 原生支持在组件中渲染 <title>、<meta> 和 <link> 标签。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function BlogPost({ post }) { return ( <article> {/* 直接在组件中添加元数据 */} <title>{post.title} - 我的博客</title> <meta name="description" content={post.excerpt} /> <meta property="og:title" content={post.title} /> <meta property="og:image" content={post.coverImage} /> <link rel="canonical" href={`https://myblog.com/posts/${post.slug}`} />
<h1>{post.title}</h1> <div>{post.content}</div> </article> ); }
|
2. 样式表优先级
React 19 改进了样式表的加载和优先级管理。
1 2 3 4 5 6 7 8 9 10 11
| function Component() { return ( <> {/* React 会自动处理样式表的优先级 */} <link rel="stylesheet" href="/styles/base.css" precedence="default" /> <link rel="stylesheet" href="/styles/theme.css" precedence="high" /> <div className="content">内容</div> </> ); }
|
3. 异步脚本支持
1 2 3 4 5
| function Analytics() { return ( <script async src="https://analytics.example.com/script.js" /> ); }
|
4. 资源预加载
React 19 提供了新的 API 用于资源预加载。
1 2 3 4 5 6 7 8 9 10 11
| import { preload, preinit } from 'react-dom';
function MyComponent() { preload('/api/data.json', { as: 'fetch' }); preinit('/scripts/analytics.js', { as: 'script' });
return <div>内容</div>; }
|
5. ref 回调的清理函数
ref 回调现在可以返回清理函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function VideoPlayer() { return ( <video ref={(node) => { if (node) { // 设置 node.play(); // 返回清理函数 return () => { node.pause(); }; } }} src="/video.mp4" /> ); }
|
6. Context 作为 Provider
不再需要 .Provider,直接使用 Context 即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { createContext } from 'react';
const ThemeContext = createContext('light');
function App() { return ( <ThemeContext value="dark"> <Page /> </ThemeContext> ); }
function App() { return ( <ThemeContext.Provider value="dark"> <Page /> </ThemeContext.Provider> ); }
|
7. useDeferredValue 的初始值
1 2 3 4 5 6 7 8
| import { useDeferredValue } from 'react';
function SearchResults({ query }) { const deferredQuery = useDeferredValue(query, '');
return <Results query={deferredQuery} />; }
|
总结
React 19 带来了许多激动人心的新特性:
核心改进
- ref 简化:不再需要
forwardRef,直接在 props 中接收 ref
- use Hook:革命性的新 Hook,可在条件语句和循环中使用
- Actions:优雅的异步操作管理方案
- 表单增强:
useActionState、useFormStatus 简化表单处理
性能优化
- useOptimistic:乐观更新提升用户体验
- 文档元数据:原生支持 SEO 标签
- 资源管理:改进的样式表和脚本加载
开发体验
- 更简洁的 API:Context 不再需要
.Provider
- 更好的类型支持:TypeScript 集成更完善
- 向后兼容:平滑的迁移路径
迁移建议
- 渐进式升级:不需要一次性重写所有代码
- 从新功能开始:在新组件中尝试 React 19 特性
- 移除 forwardRef:逐步移除
forwardRef 包装
- 使用 Actions:用 Actions 替代手动的加载状态管理
- 采用 use Hook:在合适的场景使用
use 简化代码
React 19 是一个重大更新,它简化了开发流程,提升了性能,并引入了更符合现代 Web 开发需求的新特性。建议开发者尽早熟悉这些新特性,为项目升级做好准备。