React 19 是 React 生态系统的一次重大更新,引入了多项新特性和改进,旨在简化开发流程、提升应用性能,并优化用户体验。
总结
- compiler
- use()
- useOptimistic
- useFormStatus、useFormState
- Server Components
- Directives
- Suspense
- forwardRef改进
第一点 React Compiler:自动优化,告别手动 Memoization
心智负担瞬间少了一半。
React 19 引入了全新的编译器,能够自动优化 React 代码,减少开发者手动使用 useMemo
、useCallback
和 memo
的需求。编译器将 React 代码转换为高效的 JavaScript,提升性能并简化代码。
js
const ExpensiveComponent = () => {
const [count, setCount] = useState(0);
const expensiveCalculation = useMemo(() => {
let sum = 0;
for (let i = 0; i < 1000000000; i++) sum += i;
return sum;
}, [count]);
return <div>{expensiveCalculation}</div>;
};
React 18:需要手动优化,需自己添加useMemo
。
js
const ExpensiveComponent = () => {
const [count, setCount] = useState(0);
const expensiveCalculation = () => {
let sum = 0;
for (let i = 0; i < 1000000000; i++) sum += i;
return sum;
};
return <div>{expensiveCalculation}</div>;
};
React 19:自动优化。解释 :React 19 的编译器会自动处理性能优化,开发者无需再手动编写 useMemo
或 useCallback
。
第二点 use()
Hook:简化异步操作与 Context 消费
use()
是 React 19 引入的一个多功能 Hook,用于处理异步操作(如数据获取)和 Context 消费。它可以替代 useEffect
和 useContext
,使代码更加简洁。
js
// React 18:手动管理异步状态
const DataFetchingComponent = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchData().then(setData).catch(setError).finally(() => setLoading(false));
}, []);
if (loading) return <p>加载中...</p>;
if (error) return <p>错误: {error}</p>;
return <div>{JSON.stringify(data)}</div>;
};
// React 19:使用 `use()`
const DataFetchingComponent = () => {
const data = use(fetchData());
return <div>{JSON.stringify(data)}</div>;
};
解释 :use()
会在 Promise 解析前挂起组件,并自动处理错误边界,简化了异步操作的管理。
js
import { createContext, use } from 'react';
// 创建一个上下文
const ThemeContext = createContext('light');
function ThemedButton() {
// 使用 use 消费上下文数据
const theme = use(ThemeContext);
return (
<button style={{ background: theme === 'dark' ? '#333' : '#eee', color: theme === 'dark' ? '#fff' : '#000' }}>
当前主题: {theme}
</button>
);
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}
export default App;
js
// 使用 useContext
import { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button>当前主题: {theme}</button>;
}
// 使用 use
import { createContext, use } from 'react';
const ThemeContext = createContext('light');
function ThemedButton() {
const theme = use(ThemeContext);
return <button>当前主题: {theme}</button>;
}
解释:用use,不用useContext拿上下文了。use
替代了useContext
。
第三点 useOptimistic
:乐观更新,提升用户体验
useOptimistic
允许开发者在异步操作完成前立即更新 UI,提供即时反馈,从而提升用户体验。这在聊天应用或表单提交中非常有用。
js
function ChatApp() {
const [messages, setMessages] = useState([]);
const [optimisticMessages, addOptimisticMessage] = useOptimistic(messages, (state, newMessage) => [
...state,
{ text: newMessage, sending: true },
]);
const handleSubmit = async (message) => {
addOptimisticMessage(message);
await serverAPI(message); // 模拟服务器请求
setMessages((prev) => [...prev, { text: message, sending: false }]);
};
return (
<div>
{optimisticMessages.map((msg, index) => (
<div key={index}>{msg.text} {msg.sending && <small>(发送中...)</small>}</div>
))}
<input type="text" onBlur={(e) => handleSubmit(e.target.value)} />
</div>
);
}
解释 :useOptimistic
会在服务器响应前更新 UI,如果请求失败,则自动回滚状态。
第四点 useFormStatus
与 useFormState
:简化表单管理
React 19 引入了 useFormStatus
和 useFormState
,用于简化表单状态管理和提交逻辑。useFormStatus
可以获取表单的提交状态,而 useFormState
则用于管理表单的状态。
js
// useFormStatus:获取表单提交状态
function SubmitButton() {
const { pending } = useFormStatus();
return <button disabled={pending}>{pending ? "提交中..." : "提交"}</button>;
}
// useFormState:管理表单状态
function MyForm() {
const [state, formAction] = useFormState(async (prevState, formData) => {
const name = formData.get("name");
if (!name) return { error: "Name is required" };
return { message: `Hello, ${name}!` };
}, null);
return (
<form action={formAction}>
<input type="text" name="name" />
<SubmitButton />
{state?.error && <p>{state.error}</p>}
{state?.message && <p>{state.message}</p>}
</form>
);
}
解释 :useFormStatus
和 useFormState
简化了表单的状态管理和提交逻辑,减少了样板代码。
第五点 Server Components:服务端渲染的进一步优化
React 19 将 Server Components 推向稳定,允许在服务器端提前渲染组件,减少客户端的渲染负担,提升页面加载速度。
js
// Server Component
export default function ServerComponent() {
const data = fetchDataFromServer(); // 服务器端数据获取
return <div>{data}</div>;
}
// 客户端引用
import ServerComponent from './ServerComponent';
function ClientComponent() {
return (
<div>
<ServerComponent />
</div>
);
}
第六点 Directives:简化组件配置
React 19 引入了 use client
和 use server
指令,用于声明客户端或服务器端组件,简化了组件配置。
js
"use client";
function ClientComponent() {
return <div>客户端渲染</div>;
}
"use server";
function ServerComponent() {
return <div>服务器端渲染</div>;
}
解释:通过指令声明组件类型,简化了配置并提升了代码可读性
第七点 Suspense
Suspense 是一个用于处理异步操作(如数据获取、代码分割等)的特性。它允许开发者在组件等待异步操作完成时,显示一个占位符
(fallback)。
js
import React, { Suspense } from 'react';
// 使用 React.lazy 动态加载组件
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<Suspense fallback={<div>加载中...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
export default App;
解释:
React.lazy
用于动态加载组件。<Suspense>
包裹异步组件,并在加载过程中显示fallback
内容。
js
import React, { Suspense } from 'react';
// 模拟一个支持 Suspense 的数据获取函数
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve("数据加载完成!"), 2000);
});
}
// 使用 Suspense 获取数据
const resource = fetchData();
function DataComponent() {
const data = resource.read(); // 假设这是一个支持 Suspense 的读取方法
return <div>{data}</div>;
}
function App() {
return (
<div>
<Suspense fallback={<div>加载数据中...</div>}>
<DataComponent />
</Suspense>
</div>
);
}
export default App;
解释:
fetchData
是一个模拟的异步数据获取函数。resource.read()
是一个支持 Suspense 的读取方法(需要数据获取库支持)。- 如果数据未加载完成,Suspense 会显示
fallback
。
js
import React, { Suspense, useState } from 'react';
function fetchData(id) {
return new Promise((resolve) => {
setTimeout(() => resolve(`数据 ${id} 加载完成!`), 2000);
});
}
function DataComponent({ id }) {
const data = fetchData(id).read(); // 假设这是一个支持 Suspense 的读取方法
return <div>{data}</div>;
}
function App() {
const [id, setId] = useState(1);
return (
<div>
<button onClick={() => setId(id + 1)}>加载下一个数据</button>
<Suspense fallback={<div>加载中...</div>}>
<DataComponent id={id} />
</Suspense>
</div>
);
}
export default App;
解释:
- 当用户点击按钮时,React 会在后台加载新数据,同时继续显示当前 UI。
- 数据加载完成后,Suspense 会更新 UI。
第八点 forwardRef
改进
19之前的用法:
js
import React, { forwardRef, useRef } from 'react';
// 子组件:使用 forwardRef 接收 ref
const Input = forwardRef((props, ref) => {
return <input type="text" ref={ref} {...props} />;
});
// 父组件
function App() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<Input ref={inputRef} />
<button onClick={focusInput}>聚焦输入框</button>
</div>
);
}
export default App;
解释:
Input
组件使用forwardRef
接收ref
,并将其传递给<input>
元素。- 父组件通过
ref
直接操作子组件的 DOM 元素。
19改进的用法:
js
import React, { useRef } from 'react';
// 子组件:直接接收 ref 作为 prop
function Input({ ref, ...props }) {
return <input type="text" ref={ref} {...props} />;
}
// 父组件
function App() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<Input ref={inputRef} />
<button onClick={focusInput}>聚焦输入框</button>
</div>
);
}
export default App;
解释:
- 在 React 19 中,
ref
可以直接作为 prop 传递给子组件,无需使用forwardRef
。 - React 会自动处理
ref
的传递。
js
import React, { useRef } from 'react';
// 子组件:提供默认 ref 值
function Input({ ref = useRef(null), ...props }) {
return <input type="text" ref={ref} {...props} />;
}
// 父组件
function App() {
return (
<div>
<Input />
</div>
);
}
export default App;
解释:
- 如果父组件没有传递
ref
,子组件会使用默认的ref
值。
js
import React, { forwardRef, useRef } from 'react';
// 高阶组件
function withLogging(WrappedComponent) {
return forwardRef((props, ref) => {
console.log('组件被渲染了');
return <WrappedComponent ref={ref} {...props} />;
});
}
// 普通组件
function Input({ ref, ...props }) {
return <input type="text" ref={ref} {...props} />;
}
// 使用高阶组件包裹 Input
const InputWithLogging = withLogging(Input);
// 父组件
function App() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<InputWithLogging ref={inputRef} />
<button onClick={focusInput}>聚焦输入框</button>
</div>
);
}
export default App;
解释:
withLogging
是一个高阶组件,使用forwardRef
确保ref
被正确传递到Input
组件。
总结
- compiler ------ 自动优化,无需手动加
useCallback
、useMemo
、memo
。 - use() ------ 用use替代
useContext
、useEffect
。 - useOptimistic ------ 乐观做事,慢的时候,先提示用户不让用户干等。
- useFormStatus、useFormState ------ 表单的钩子:status获取状态,state一个获取数据。
- Server Components ------ 服务器端提前渲染组件,减少客户端渲染工作量,提高性能,做seo优化很好用。
- Directives ------ 混合渲染,用来区分服务器端的代码和客户端代码,提高可读性。
- Suspense ------ 占位,加载的过程,先提示,回来东西再渲染正文。
- forwardRef改进 ------ 可不用forwardRef,直接用props拿值。