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>
  );
}
相关推荐
杨进军5 小时前
React 实现 useMemo
前端·react.js·前端框架
杨进军5 小时前
React 实现多个节点 diff
前端·react.js·前端框架
杨进军5 小时前
React 实现 useState
前端·react.js·前端框架
goldenocean9 小时前
React之旅-05 List Key
前端·javascript·react.js
杨进军12 小时前
React 实现节点删除
前端·react.js·前端框架
爱编程的喵12 小时前
React useContext 深度解析:告别组件间通信的噩梦
前端·react.js
赫本的猫13 小时前
告别生命周期!用Hooks实现更优雅的React开发
前端·react.js·面试
赫本的猫13 小时前
React中的路由艺术:用react-router-dom实现无缝页面切换
前端·react.js·面试
光影少年13 小时前
React 组件中怎么做事件代理?它的原理是什么?
前端·react.js·掘金·金石计划