react中hooks之 React 19 新 Hooks useOptimistic

概述

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

基本语法

typescript 复制代码
const [optimisticState, addOptimistic] = useOptimistic<State, Patch>(
  state,
  updateFn
);

参数说明

  1. state: 当前状态值

    • 可以是任何类型的值
    • 作为乐观更新的基础状态
  2. updateFn: 更新函数

    • 类型: (currentState: State, patch: Patch) => State
    • 接收当前状态和更新补丁
    • 返回新的乐观状态

返回值

typescript 复制代码
type UseOptimisticReturn<State, Patch> = [
  State,                      // 乐观状态
  (patch: Patch) => void      // 触发乐观更新的函数
];

使用示例

1. 基础点赞功能

typescript 复制代码
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. 评论列表

typescript 复制代码
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. 复杂状态更新

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

注意事项

  1. 性能考虑:

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

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

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

总结

  1. useOptimistic 优点:

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

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

    • 合理处理错误情况
    • 实现优雅的回滚机制
    • 注意状态一致性
    • 优化性能表现
相关推荐
2501_9444480043 分钟前
Flutter for OpenHarmony衣橱管家App实战:支持我们功能实现
android·javascript·flutter
人工智能训练6 小时前
【极速部署】Ubuntu24.04+CUDA13.0 玩转 VLLM 0.15.0:预编译 Wheel 包 GPU 版安装全攻略
运维·前端·人工智能·python·ai编程·cuda·vllm
会跑的葫芦怪7 小时前
若依Vue 项目多子路径配置
前端·javascript·vue.js
2601_949593657 小时前
基础入门 React Native 鸿蒙跨平台开发:模拟智能音响
react native·react.js·harmonyos
xiaoqi9228 小时前
React Native鸿蒙跨平台如何进行狗狗领养中心,实现基于唯一标识的事件透传方式是移动端列表开发的通用规范
javascript·react native·react.js·ecmascript·harmonyos
jin1233228 小时前
React Native鸿蒙跨平台剧本杀组队消息与快捷入口组件,包含消息列表展示、快捷入口管理、快捷操作触发和消息详情预览四大核心功能
javascript·react native·react.js·ecmascript·harmonyos
烬头882110 小时前
React Native鸿蒙跨平台实现二维码联系人APP(QRCodeContactApp)
javascript·react native·react.js·ecmascript·harmonyos
pas13610 小时前
40-mini-vue 实现三种联合类型
前端·javascript·vue.js
摇滚侠10 小时前
2 小时快速入门 ES6 基础视频教程
前端·ecmascript·es6
2601_9498333910 小时前
flutter_for_openharmony口腔护理app实战+预约管理实现
android·javascript·flutter