React 19 新特性之useActionState
- Published on
- Reading time
- 6 min read
- Likes
Actions背景
官方文档 useActionState – React 中文文档useActionState – React 中文文档The library for web and native user interfaces
下面是一个用更通俗易懂的语言来描述「React 19 中的 Actions」及其与 Suspense 区别的版本:
- Actions 是 React 19 的重头戏
- 传统的 React(或说 React 18 及之前)通常使用 Suspense 来处理数据获取时的异步操作,比如从服务器拿数据。
- 但是,用 Suspense 去处理时, 像 POST、PUT 等这种更新数据的异步操作就比较麻烦
- React 19 就给我们提供了"Actions"这个新东西,专门处理"更新数据"的异步操作。
- Actions 与 Server Components 深度集成,可以直接在服务器端执行,减少客户端代码量
- Suspense请求 和 Actions请求 的主要区别
- Suspense:处理读取数据的异步操作。比如页面一加载,就去 fetch 一个接口,拿到数据再渲染。
- Actions:处理更新数据的异步操作。比如用户提交表单,需要 POST 到服务器,然后刷新页面或更新界面。
- 为什么要引入 Actions
- 之前如果我们要处理 POST 之类的更新操作,只能自己写一堆手动的异步流程(例如 then/catch 或 async/await),可能还要维护 loading 状态、错误处理、刷新界面等逻辑。
- React 19 的 Actions 相当于把这些常见场景(更新数据的异步操作)直接封装成了一个更统一的"官方方案",写起来更"傻瓜",也更容易维护。
Actions案例场景
在实际开发中,异步操作非常常见,比如:
- 表单提交
- 请求后端接口
- 上传或下载文件
- 第三方 API 调用
- 状态管理和数据同步
- 实时数据更新和推送
每当我们执行这些"动作"(action)时,往往需要管理多个状态:
- 是否正在加载中(loading)
- 请求是否成功(success)
- 请求是否失败(error)
- 成功或失败返回的数据(result / data / errorMessage 等)
常见的痛点在于,我们需要手动去写一堆 useState 或者分散到各种逻辑里,比如:
tsxEavan.dev
function MyComponent() {
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const [data, setData] = useState(null)
const handleSubmit = async () => {
try {
setLoading(true)
setError(null)
const result = await submitForm() // 异步操作
setData(result)
} catch (e) {
setError(e)
} finally {
setLoading(false)
}
}
// ...
}
每次都要重复一大堆类似的逻辑,而且要特别小心在 组件卸载, 竞态 等情况下是否需要清理或终止异步操作。
有些人会借助第三方库(如 react-query、swr 等)来统一管理这些请求状态;也有些人会写一个自定义 Hook,比如 useFetch、useMutation,试图把"异步动作"的状态管理和逻辑封装起来,简化使用。
useActionState想解决什么问题?
- 避免样板代码 我们不希望在每个组件里都重复写 loading / error / data 这三四个状态以及请求逻辑的 try-catch-finally。一次封装,多处使用。
- 一站式管理异步状态 在封装层里,自动帮助我们管理"发起请求、结束请求、成功、失败"这些状态,并提供一个简洁的 API 返回给组件使用。
- 更好的语义和开发体验 使用者只需要关心:"我想要执行一个 action";而组件内部可以更轻松地拿到 loading、data 等信息。例如:
jsxEavan.dev
import {useActionState} from "react";
function MyComponent() {
// 使用 useActionState 管理状态和异步操作
const [state, handleSubmit, isLoading] = useActionState(async (_prevState, formData: FormData) => {
try {
// 调用异步操作(如 API 请求)
const result = await submitForm(); // 替换为你的异步操作
return { data: result, error: null }; // 返回成功结果
} catch (error) {
return { data: null, error }; // 返回错误结果
}
}, { data: null, error: null });
return (
<div>
{/* 表单提交 */}
<form action={handleSubmit}>
<button type="submit" disabled={isLoading}>
{isLoading ? "正在提交..." : "提交"}
</button>
</form>
{/* 状态显示 */}
{state.error && <p style={{ color: "red" }}>错误: {state.error.message}</p>}
{state.data && <p>成功: {JSON.stringify(state.data)}</p>}
</div>
);
}
// 模拟异步操作函数
const submitForm = async () => {
// 模拟 API 延迟
await new Promise((resolve) => setTimeout(resolve, 2000));
return { success: true, message: "提交成功!" }; // 模拟返回结果
};
当组件调用 submitForm(someData) 时,useActionState 会自动帮我们管理 loading、error、data 等状态,而我们只需要关心"发起请求"和"请求成功后的处理"即可。
注意: 在服务端中,userActionState与客户端中的useActionState是有些不同的
如未标记非原创,转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,未经站长允许不得对文章文字内容进行修改演绎,不得用于商业目的。
本文采用CC BY-NC-SA 4.0 - 非商业性使用 - 相同方式共享 4.0 国际进行许可。
本文采用CC BY-NC-SA 4.0 - 非商业性使用 - 相同方式共享 4.0 国际进行许可。