React 19 新 API:并发特性与表单交互
Transition、useOptimistic、useFormStatus、useFormState——React 19 引入的核心 API 及其设计意图
React 19 在 RSC 之外,带来了一批面向用户交互的新 API。它们的共同目标是:让异步操作和表单交互有更好的 UX,同时不让开发者手动管理 loading/error 状态。
一、Transition:区分紧急与非紧急更新
问题
用户输入 → 触发搜索 → 结果列表更新。如果结果计算很慢,输入框也会卡顿——因为 React 默认把所有更新视为同等优先级。
解决
import { useTransition } from 'react'
function SearchBox() {
const [isPending, startTransition] = useTransition()
const [query, setQuery] = useState('')
const [results, setResults] = useState([])
function handleChange(e) {
setQuery(e.target.value) // 紧急:输入框立刻响应
startTransition(() => {
setResults(search(e.target.value)) // 非紧急:可以被打断
})
}
return (
<>
<input value={query} onChange={handleChange} />
{isPending ? <Spinner /> : <ResultList results={results} />}
</>
)
}
startTransition 内的更新优先级降低,可以被更紧急的更新(比如用户继续输入)打断。isPending 告诉你是否有挂起的 transition,用来显示 loading 状态。
React 19 的扩展
React 19 之前,startTransition 只支持同步函数。React 19 开始支持 async:
startTransition(async () => {
const data = await fetchResults(query)
setResults(data)
})
Transition 从“优先级调度”扩展到了“异步操作管理”。
二、useOptimistic:乐观更新的标准写法
问题
点赞按钮:用户点击 → 等待服务端响应 → 更新 UI。这个延迟让交互感觉迟钝。乐观更新的做法是先假设成功、立刻更新 UI,失败了再回滚。
以前要手动管理这套逻辑,容易出错。
解决
import { useOptimistic } from 'react'
function LikeButton({ postId, initialLikeCount }) {
const [likeCount, setLikeCount] = useState(initialLikeCount)
const [optimisticCount, addOptimistic] = useOptimistic(
likeCount,
(current, increment) => current + increment
)
async function handleLike() {
addOptimistic(1) // 立刻 +1
try {
await likePost(postId)
setLikeCount(c => c + 1) // 服务端确认后更新真实值
} catch {
// 自动回滚到 likeCount
}
}
return (
<button onClick={handleLike}>
♥ {optimisticCount}
</button>
)
}
useOptimistic 接受真实值和更新函数,返回乐观值。异步操作完成后自动同步回真实值,失败自动回滚。不需要手动写回滚逻辑。
三、useFormStatus:表单子组件感知提交状态
问题
Submit 按钮需要在表单提交时 disable 并显示 loading,但它通常是一个子组件,拿不到父级表单的提交状态。以前要靠 prop drilling 或 context 传递。
解决
import { useFormStatus } from 'react-dom'
function SubmitButton() {
const { pending } = useFormStatus()
return (
<button disabled={pending}>
{pending ? '提交中...' : '提交'}
</button>
)
}
function ContactForm() {
return (
<form action={submitAction}>
<input name="email" type="email" />
<SubmitButton /> {/* 自动感知表单状态,无需传 prop */}
</form>
)
}
useFormStatus 只能在 <form> 的子组件里用,自动订阅最近的父级表单状态。pending 在表单提交期间为 true。
注意:这是 react-dom 的 hook,不是 react。
四、useFormState / useActionState:管理表单 action 的结果
问题
表单提交 → 服务端 action → 返回结果(成功/错误信息)。如何把这个结果回传给客户端组件?
解决
import { useActionState } from 'react' // React 19 重命名为 useActionState
async function submitForm(prevState, formData) {
const email = formData.get('email')
if (!email.includes('@')) {
return { error: '邮箱格式不正确' }
}
await saveEmail(email)
return { success: true }
}
function ContactForm() {
const [state, formAction, isPending] = useActionState(submitForm, null)
return (
<form action={formAction}>
<input name="email" type="email" />
{state?.error && <p className="error">{state.error}</p>}
{state?.success && <p>提交成功!</p>}
<button disabled={isPending}>
{isPending ? '提交中...' : '提交'}
</button>
</form>
)
}
useActionState 接受 action 函数和初始状态,返回当前状态、包装后的 action 和 pending 状态。action 函数接收上一次的状态和 FormData,返回新状态。
React 19 将
useFormState(来自 react-dom)重命名为useActionState(来自 react),同时新增了isPending返回值。
五、三个 API 的协作
实际场景里这三个 API 经常一起出现:
function CommentForm({ postId }) {
const [state, formAction, isPending] = useActionState(
submitComment,
null
)
const [optimisticComments, addOptimistic] = useOptimistic(
comments,
(prev, newComment) => [...prev, newComment]
)
return (
<>
<CommentList comments={optimisticComments} />
<form action={async (formData) => {
addOptimistic({ text: formData.get('text'), pending: true })
await formAction(formData)
}}>
<textarea name="text" />
<SubmitButton /> {/* useFormStatus 在内部 */}
{state?.error && <p>{state.error}</p>}
</form>
</>
)
}
useActionState管理服务端响应useOptimistic立刻更新 UIuseFormStatus让 SubmitButton 自动感知状态
三者分工明确,各司其职。
核心结论
React 19 的这批 API 有一个共同设计原则:把异步操作的状态管理标准化,从组件里剥离出去。
以前要手动维护 isLoading、error、optimisticValue 这些状态,逻辑分散容易出 bug。现在 React 内置了这些模式,让你专注于业务逻辑本身。
| API | 解决什么 |
|---|---|
useTransition |
区分紧急/非紧急更新,async 支持 |
useOptimistic |
乐观更新 + 自动回滚 |
useFormStatus |
子组件感知表单提交状态 |
useActionState |
管理 action 返回值和 pending 状态 |