React19 useOptimistic 用法

用法

乐观更新

  • 发起异步请求时,先假设请求会成功
  • 立即更新 UI 给用户反馈
  • 若请求最终失败,再将 UI 恢复到之前的状态

const [optimisticState, addOptimistic] = useOptimistic(state, updateFn)

参数
state:实际值,可以是 useStateuseReduceruseContextprops
updateFn:纯函数

  • currentState
  • optimisticValue

返回值
optimisticState:乐观值

  • 正常情况下:和 state 实际值一致
  • 调用 addOptimistic 后,是 updateFn 的返回值

addOptimistic:调用updateFn,接收任意类型的 optimisticValue

注意点

  1. 要在 form ActionstartTransition 里面调用 addOptimistic
  2. 异步操作结束(无论成功还是失败),乐观值都会自动恢复成 state
    异步操作成功,需要手动 setState 更新实际值,从而更新 useOptimisticstate
    异步操作失败,不用管

测试代码

javascript 复制代码
import React, { useState, useOptimistic, startTransition } from "react";

// 模拟异步点赞请求,考虑请求失败的情况
const asyncLikePost = (postId) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // 模拟 50% 的失败概率
      if (Math.random() < 0.5) {
        reject(new Error("点赞失败"));
      } else {
        resolve();
      }
    }, 3000);
  });
};

const Post = ({ post }) => {
  const [likes, setLikes] = useState(post.likes);
  const [optimisticLikes, addOptimisticLikes] = useOptimistic(
    likes,
    (currentLikes, optimisticValue) => currentLikes + 1
  );
  const [error, setError] = useState(null);

  const handleLike = function handleLike() {
    startTransition(async () => {
      addOptimisticLikes();

      try {
        await asyncLikePost(post.id);
        setLikes((prevLikes) => prevLikes + 1);
        setError(null);
      } catch (error) {
        setError(error.message);
      }
    });
  };

  return (
    <div>
      <p>{post.title}</p>
      <p>实际点赞数: {likes}</p>
      <p>乐观点赞数: {optimisticLikes}</p>
      {error && <p style={{ color: "red" }}>{error}</p>}

      <button onClick={handleLike}>点赞</button>
    </div>
  );
};

const PostList = () => {
  const posts = [
    { id: 1, title: "帖子1", likes: 10 },
    { id: 2, title: "帖子2", likes: 20 },
  ];

  return (
    <div>
      {posts.map((post) => (
        <Post key={post.id} post={post} />
      ))}
    </div>
  );
};

export default function App() {
  return (
    <div>
      <h1>帖子列表</h1>
      <PostList />
    </div>
  );
}
相关推荐
孟陬1 小时前
HTML 处理以及性能对比 - Bun 单元测试系列
react.js·单元测试·bun
小高0072 小时前
React useMemo 深度指南:原理、误区、实战与 2025 最佳实践
前端·javascript·react.js
一颗奇趣蛋3 小时前
React.memo & useMemo:为什么 React 里「看起来没变的组件」还是渲染了
前端·react.js
Ice_Sugar_74 小时前
React 腾讯面试手写题
javascript·react.js·ecmascript
卸任5 小时前
Electron自制翻译工具:自动更新
前端·react.js·electron
小喷友7 小时前
Next.js 中的 Edge Middleware 实战
前端·react.js·next.js
前端美少女战士9 小时前
post方法下载文件,需做哪些特殊处理
javascript·react.js
Jimmy11 小时前
React 性能优化:从慢到闪电般快
前端·javascript·react.js
江城开朗的豌豆11 小时前
React Hooks 真香定律:告别Class组件,我为什么回不去了?
前端·javascript·react.js
江城开朗的豌豆12 小时前
React Component和Purecomponent区别
前端·javascript·react.js