概览useOptimistic 可在提交前立即更新 UI,降低交互延迟感。结合撤销与冲突合并策略,在后台确认失败或产生竞态时稳定回滚或合并,保证一致性与可控性。基础用法'use client'
import { useOptimistic, useState } from 'react'
type Item = { id: string; text: string }
export default function List() {
const [items, setItems] = useState<Item[]>([])
const [optimisticItems, addOptimistic] = useOptimistic(items, (state, pending: Item) => {
return [...state, pending]
})
async function add(text: string) {
const temp: Item = { id: crypto.randomUUID(), text }
addOptimistic(temp)
const ok = await submit(temp)
if (!ok) {
setItems((prev) => prev.filter((i) => i.id !== temp.id))
} else {
setItems((prev) => [...prev, temp])
}
}
return (
<div>
<button onClick={() => add('任务')}>添加</button>
<ul>
{optimisticItems.map((i) => (
<li key={i.id}>{i.text}</li>
))}
</ul>
</div>
)
}
async function submit(i: Item) {
await new Promise((r) => setTimeout(r, 400))
return Math.random() > 0.2
}
撤销与冲突合并'use client'
import { useOptimistic, useRef, useState } from 'react'
type Change = { id: string; text: string }
export function Editor() {
const [base, setBase] = useState<string>('')
const [optimistic, apply] = useOptimistic(base, (state, change: Change) => change.text)
const queue = useRef<Change[]>([])
async function save(next: string) {
const change: Change = { id: crypto.randomUUID(), text: next }
apply(change)
queue.current.push(change)
const ok = await commit(change)
if (!ok) {
// 合并策略:回退到最新成功版本
const last = queue.current.at(-2)
setBase(last ? last.text : base)
} else {
setBase(next)
}
}
return (
<div>
<textarea defaultValue={base} onBlur={(e) => save(e.target.value)} />
<p>预览:{optimistic}</p>
</div>
)
}
async function commit(c: Change) {
await new Promise((r) => setTimeout(r, 500))
return true
}
治理要点对失败场景提供撤销或回滚保障,避免状态撕裂。合并策略以最新成功提交为基线,减少竞态污染。与 Server Actions 协作,将幂等与去重纳入后端保障。验证与指标React:19.0+;Next.js:15.0+即时反馈:按钮与文本在 100–200ms 内出现乐观更新;失败可在 1s 内回滚

发表评论 取消回复