React 19 新特性之useActionState

Published on
Reading time
6 min read
Likes
Authors

Actions背景

官方文档 useActionState – React 中文文档 faviconuseActionState – React 中文文档

下面是一个用更通俗易懂的语言来描述「React 19 中的 Actions」及其与 Suspense 区别的版本:

  1. Actions 是 React 19 的重头戏
  • 传统的 React(或说 React 18 及之前)通常使用 Suspense 来处理数据获取时的异步操作,比如从服务器拿数据。
  • 但是,用 Suspense 去处理时, 像 POST、PUT 等这种更新数据的异步操作就比较麻烦
  • React 19 就给我们提供了"Actions"这个新东西,专门处理"更新数据"的异步操作。
  • Actions 与 Server Components 深度集成,可以直接在服务器端执行,减少客户端代码量
  1. Suspense请求 和 Actions请求 的主要区别
  • Suspense:处理读取数据的异步操作。比如页面一加载,就去 fetch 一个接口,拿到数据再渲染。
  • Actions:处理更新数据的异步操作。比如用户提交表单,需要 POST 到服务器,然后刷新页面或更新界面。
  1. 为什么要引入 Actions
  • 之前如果我们要处理 POST 之类的更新操作,只能自己写一堆手动的异步流程(例如 then/catch 或 async/await),可能还要维护 loading 状态、错误处理、刷新界面等逻辑。
  • React 19 的 Actions 相当于把这些常见场景(更新数据的异步操作)直接封装成了一个更统一的"官方方案",写起来更"傻瓜",也更容易维护。
图片

Actions案例场景

在实际开发中,异步操作非常常见,比如:

  • 表单提交
  • 请求后端接口
  • 上传或下载文件
  • 第三方 API 调用
  • 状态管理和数据同步
  • 实时数据更新和推送

每当我们执行这些"动作"(action)时,往往需要管理多个状态:

  1. 是否正在加载中(loading)
  2. 请求是否成功(success)
  3. 请求是否失败(error)
  4. 成功或失败返回的数据(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想解决什么问题?

  1. 避免样板代码 我们不希望在每个组件里都重复写 loading / error / data 这三四个状态以及请求逻辑的 try-catch-finally。一次封装,多处使用。
  2. 一站式管理异步状态 在封装层里,自动帮助我们管理"发起请求、结束请求、成功、失败"这些状态,并提供一个简洁的 API 返回给组件使用。
  3. 更好的语义和开发体验 使用者只需要关心:"我想要执行一个 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是有些不同的

参考链接

感谢以下资源的帮助和启发: