乐观更新(Optimistic Update)是指在服务端确认之前,先假设操作会成功并立即更新 UI,让用户感知不到网络延迟。如果后续服务端返回失败,再回滚到之前的状态。这种模式在点赞、收藏、评论等即时反馈场景中非常常见。
在 React 19 之前,实现乐观更新通常需要手动维护“临时状态 + 回滚逻辑”,或者借助 React Query、Redux 等外部库。React 19 提供了原生的 useOptimistic Hook,将这一模式固化为框架层的能力。
基本用法
useOptimistic 接收两个参数:
- 原始状态(通常是来自服务端或父组件的“真实数据”)
- 更新函数:定义如何基于当前状态和乐观值产出新的 UI 状态
它返回一个数组:
- 乐观状态:在等待服务端响应期间立即展示给用户的状态
- 添加乐观更新:一个函数,调用它时会立即应用更新函数,并在异步操作完成后自动恢复为原始状态
import { useOptimistic } from 'react';
function LikeButton({ initialLiked, initialCount, onToggle }) {
// initialLiked 和 initialCount 来自服务端或父组件
const [optimisticState, addOptimistic] = useOptimistic(
{ liked: initialLiked, count: initialCount },
(currentState, newLiked) => ({
liked: newLiked,
count: newLiked ? currentState.count + 1 : currentState.count - 1,
})
);
const handleClick = async () => {
const newLiked = !optimisticState.liked;
// 立即应用乐观更新
addOptimistic(newLiked);
// 发送真实请求
try {
await onToggle(newLiked);
} catch {
// 请求失败时,useOptimistic 会自动回滚到原始状态
// 无需手动处理
}
};
return (
<button onClick={handleClick}>
{optimisticState.liked ? '❤️ 已赞' : '🤍 点赞'} ({optimisticState.count})
</button>
);
}
核心思路是:先假设成功 → 立即更新 UI → 等待服务端确认。如果服务端操作失败(抛出异常),useOptimistic 会自动丢弃乐观更新,将状态恢复为最后一次未更新的原始值。
与 React 19 的 Server Actions 配合
React 19 的 Server Actions 可以直接与 useOptimistic 结合,实现端到端的乐观更新:
import { useOptimistic } from 'react';
import { toggleLikeAction } from './actions';
function Post({ post }) {
const [optimisticPost, addOptimistic] = useOptimistic(
post,
(currentPost, newLiked) => ({
...currentPost,
liked: newLiked,
likesCount: newLiked ? currentPost.likesCount + 1 : currentPost.likesCount - 1,
})
);
async function handleLike() {
const newLiked = !optimisticPost.liked;
addOptimistic(newLiked); // 乐观更新
await toggleLikeAction(post.id, newLiked); // Server Action
}
return (
<div>
<h3>{optimisticPost.title}</h3>
<button onClick={handleLike}>
{optimisticPost.liked ? '❤️' : '🤍'} {optimisticPost.likesCount}
</button>
</div>
);
}
如果 toggleLikeAction 在服务端执行失败,它会抛出错误,useOptimistic 自动将 optimisticPost 回滚到 post 的最新值,用户看到的点赞按钮会恢复到操作前的状态。
实际开发中的注意点
- 自动回滚机制
乐观更新只在发起 addOptimistic 的同步函数或异步函数的第一个 await 之前生效。一旦异步操作完成(无论成功或失败),React 都会根据传入的新原始状态重新计算 UI——如果原始状态已更新,则乐观状态自然与之一致;如果异步操作抛错,原始状态未变,则乐观状态被丢弃。因此不需要手动回滚。
- 不要直接修改原始状态
useOptimistic 返回的乐观状态是只读快照,不能直接赋值修改。所有变更都应通过 addOptimistic 进行。
- 复杂场景的组合使用
useOptimistic 可以和其他 Hook(如 useActionState、useTransition)组合,处理表单提交、多步操作等复杂交互。它更多是一种展示层的即时反馈机制,底层仍然依赖真实状态更新来同步。
- 适用边界
对于确定性很高且用户对延迟敏感的操作(如点赞、拖拽排序、文本编辑),useOptimistic 是最佳选择。但对转账、订单提交等关键操作,建议谨慎使用乐观更新,或仅将其用于临时加载提示而非真实数据展示。
与传统实现方式的对比
| 传统方式 | useOptimistic |
|---------|---------------|
| 需要手动创建临时状态变量 | 框架自动管理乐观状态 |
| 需在 try-catch 中手动回滚 | 自动回滚,减少样板代码 |
| 状态逻辑散落在多个地方 | 状态更新逻辑集中在一个更新函数 |
| 需处理竞态条件(快速连续点击) | React 内部处理序列,保证状态一致性 |
useOptimistic 的出现,进一步强化了 React 19 作为“全栈框架核心库”的定位,让前端常见的用户体验优化模式变得内建且标准化。