概述
useOptimistic 是 React 19 引入的新 Hook,用于实现乐观更新(Optimistic Updates)。它允许你在等待异步操作完成时立即更新 UI,提供更好的用户体验。
基本语法
const [optimisticState, addOptimistic] = useOptimistic<State, Patch>(state,updateFn
);
参数说明
-
state: 当前状态值
- 可以是任何类型的值
- 作为乐观更新的基础状态
-
updateFn: 更新函数
- 类型:
(currentState: State, patch: Patch) => State
- 接收当前状态和更新补丁
- 返回新的乐观状态
- 类型:
返回值
type UseOptimisticReturn<State, Patch> = [State, // 乐观状态(patch: Patch) => void // 触发乐观更新的函数
];
使用示例
1. 基础点赞功能
function LikeButton({ id, initialLikes }: { id: string; initialLikes: number }) {const [likes, setLikes] = useState(initialLikes);const [optimisticLikes, addOptimisticLike] = useOptimistic(likes,(currentLikes: number, addedLikes: number) => currentLikes + addedLikes);async function handleLike() {addOptimisticLike(1); // 立即更新 UItry {const response = await fetch(`/api/like/${id}`, { method: 'POST' });const newLikes = await response.json();setLikes(newLikes); // 更新实际状态} catch (error) {// 错误处理setLikes(likes); // 回滚到原始状态}}return (<button onClick={handleLike}>Likes: {optimisticLikes}</button>);
}
2. 评论列表
interface Comment {id: string;text: string;author: string;
}function CommentList() {const [comments, setComments] = useState<Comment[]>([]);const [optimisticComments, addOptimisticComment] = useOptimistic<Comment[],Comment>(comments,(currentComments, newComment) => [...currentComments, newComment]);async function handleAddComment(text: string) {const optimisticComment = {id: 'temp-' + Date.now(),text,author: 'Current User',};addOptimisticComment(optimisticComment);try {const response = await fetch('/api/comments', {method: 'POST',body: JSON.stringify({ text }),});const savedComment = await response.json();setComments([...comments, savedComment]);} catch (error) {// 错误处理,回滚setComments(comments);}}return (<div><CommentForm onSubmit={handleAddComment} /><ul>{optimisticComments.map(comment => (<CommentItem key={comment.id} comment={comment} />))}</ul></div>);
}
3. 复杂状态更新
interface TodoItem {id: string;text: string;completed: boolean;
}function TodoList() {const [todos, setTodos] = useState<TodoItem[]>([]);const [optimisticTodos, addOptimisticUpdate] = useOptimistic<TodoItem[],{ id: string; completed: boolean }>(todos,(currentTodos, update) => currentTodos.map(todo => todo.id === update.id ? { ...todo, completed: update.completed }: todo));async function toggleTodo(id: string, completed: boolean) {addOptimisticUpdate({ id, completed });try {await fetch(`/api/todos/${id}`, {method: 'PATCH',body: JSON.stringify({ completed }),});} catch (error) {// 回滚setTodos(todos);}}return (<ul>{optimisticTodos.map(todo => (<TodoItemkey={todo.id}todo={todo}onToggle={toggleTodo}/>))}</ul>);
}
最佳实践
- 错误处理与回滚
function useOptimisticAction<T, P>(initialState: T,updateFn: (state: T, patch: P) => T,actionFn: (patch: P) => Promise<T>
) {const [state, setState] = useState<T>(initialState);const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);async function performAction(patch: P) {addOptimistic(patch);try {const result = await actionFn(patch);setState(result);} catch (error) {setState(state); // 回滚throw error;}}return [optimisticState, performAction] as const;
}
- 与 Suspense 集成
function AsyncList() {return (<Suspense fallback={<Skeleton />}><OptimisticList /></Suspense>);
}
注意事项
-
性能考虑:
- 避免在更新函数中进行复杂计算
- 合理使用 useMemo 缓存计算结果
- 注意大型列表的渲染优化
-
状态一致性:
- 保持乐观更新和实际状态的同步
- 实现合适的回滚机制
- 处理并发更新情况
-
用户体验:
- 提供适当的加载状态指示
- 实现平滑的状态转换
- 处理错误情况下的用户反馈
总结
-
useOptimistic 优点:
- 提升用户体验
- 减少感知延迟
- 支持复杂状态更新
- 易于实现回滚
-
适用场景:
- 点赞/收藏功能
- 评论系统
- 待办事项列表
- 表单提交
- 数据列表操作
-
使用建议:
- 合理处理错误情况
- 实现优雅的回滚机制
- 注意状态一致性
- 优化性能表现