735 字
4 分钟
useActionState

它管的是「动作的结果」#

const [state, dispatchAction, isPending] = useActionState(
reducerAction,
initialState,
permalink?
)

三个返回值分别是:当前状态、触发函数、进行中标记。

第一个参数 reducerAction(previousState, actionPayload) 与 useReducer 的 reducer 形状相同,但有一条关键差别:它可以异步,也可以有副作用。官方的说法是把 useActionState 当成「带副作用的 useReducer」。

它是 React 19 新增的(实验期叫 ReactDOM.useFormState,稳定时改名)。

一个例子#

import { useActionState } from 'react'
async function updateName(prevState, formData) {
const name = formData.get('name')
if (!name) {
return '名字不能为空'
}
await saveName(name)
return null
}
function NameForm() {
const [error, dispatchAction, isPending] = useActionState(updateName, null)
return (
<form action={dispatchAction}>
<input name="name" disabled={isPending} />
<button type="submit">保存</button>
{error && <p>{error}</p>}
</form>
)
}

把 dispatchAction 直接交给 <form action>,React 会替你包一层过渡,成功后表单还会自动重置。

注意参数的错位:普通的表单 action 第一个参数是 FormData,用了 useActionState 之后它变成第二个,第一个固定是上一次的状态。

五条规则#

dispatchAction 必须在过渡里调用。传给 <form action> 或组件的 action prop 时 React 自动处理;自己手动调,就要用 startTransition 包住,否则 isPending 不更新,控制台还会报「called outside of a transition」。

队列是串行的。每次调用都会等到上一次结束,并把上一次的返回值当作 previousState 传进来。官方说这是有意设计:不给上一个结果就没法算下一个。代价是连点四下就排四次队、依次执行。要在等待期间立即给反馈,配 useOptimistic。

已知错误用返回值,未知错误才抛。校验失败之类的可预期错误,return 成状态显示在界面上;真正异常(代码 bug)抛出去,React 会取消队列里剩下的动作并交给最近的错误边界。

它没有内置的重置函数。想清空,就在 reducerAction 里认一个约定的重置信号;或者给组件加 key 强制重挂载;用 <form action> 时提交成功本来就会重置。

不要在渲染期间调用 dispatchAction。那会造成渲染、派发、再渲染的循环,React 会直接报错拦住。

另外一条与 useReducer 相反的细节:reducerAction 在严格模式下不会被调用两次,因为它本来就允许有副作用。

与 useReducer 的分工#

官方把界限划得很清楚:useReducer 管界面状态,reducer 必须是纯函数;useActionState 管动作的状态,reducer 允许异步与副作用。需要并行执行的动作,用 useState 加 useTransition 自己做,别硬塞进这个 Hook。

服务端渲染#

配 Server Functions 时,初始状态需要可序列化(普通对象、数组、字符串、数字)。第三个参数 permalink 是给渐进增强用的:JavaScript 还没加载完就提交表单时,浏览器会导航到那个地址,而不是当前页面。这一层通常由框架处理,业务代码很少直接写。

第 31 篇,共 39 篇本文属于系列

useActionState
https://www.choria.top/posts/hook-use-action-state/
作者
乔瑞雅·克林威尔
发布于
2026-05-02
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取

最后更新于 ,距今已过 190 天

部分内容可能已过时