用法
乐观更新
- 发起异步请求时,先假设请求会成功
- 立即更新 UI 给用户反馈
- 若请求最终失败,再将 UI 恢复到之前的状态
const [optimisticState, addOptimistic] = useOptimistic(state, updateFn)
参数
state
:实际值,可以是 useState
、useReducer
、useContext
、props
updateFn
:纯函数
currentState
optimisticValue
返回值
optimisticState
:乐观值
- 正常情况下:和
state
实际值一致 - 调用
addOptimistic
后,是updateFn
的返回值
addOptimistic
:调用updateFn
,接收任意类型的 optimisticValue
注意点
- 要在
form Action
或startTransition
里面调用addOptimistic
- 异步操作结束(无论成功还是失败),乐观值都会自动恢复成
state
异步操作成功,需要手动setState
更新实际值,从而更新useOptimistic
的state
异步操作失败,不用管
测试代码
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>
);
}