Bootstrap

react中hooks之 React 19 新 Hooks useOptimistic

概述

useOptimistic 是 React 19 引入的新 Hook,用于实现乐观更新(Optimistic Updates)。它允许你在等待异步操作完成时立即更新 UI,提供更好的用户体验。

基本语法

const [optimisticState, addOptimistic] = useOptimistic<State, Patch>(
  state,
  updateFn
);

参数说明

  1. state: 当前状态值

    • 可以是任何类型的值
    • 作为乐观更新的基础状态
  2. 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); // 立即更新 UI
    
    try {
      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 => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onToggle={toggleTodo}
        />
      ))}
    </ul>
  );
}

最佳实践

  1. 错误处理与回滚
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;
}
  1. 与 Suspense 集成
function AsyncList() {
  return (
    <Suspense fallback={<Skeleton />}>
      <OptimisticList />
    </Suspense>
  );
}

注意事项

  1. 性能考虑:

    • 避免在更新函数中进行复杂计算
    • 合理使用 useMemo 缓存计算结果
    • 注意大型列表的渲染优化
  2. 状态一致性:

    • 保持乐观更新和实际状态的同步
    • 实现合适的回滚机制
    • 处理并发更新情况
  3. 用户体验:

    • 提供适当的加载状态指示
    • 实现平滑的状态转换
    • 处理错误情况下的用户反馈

总结

  1. useOptimistic 优点:

    • 提升用户体验
    • 减少感知延迟
    • 支持复杂状态更新
    • 易于实现回滚
  2. 适用场景:

    • 点赞/收藏功能
    • 评论系统
    • 待办事项列表
    • 表单提交
    • 数据列表操作
  3. 使用建议:

    • 合理处理错误情况
    • 实现优雅的回滚机制
    • 注意状态一致性
    • 优化性能表现
;