Optimistic UI
Optimistic UI 是在等待后端响应前先在 UI 上展示预期结果的模式。在 AI 对话中,用户发送消息后立即显示在界面上,不等后端确认。
#type / concept
#status / evergreen
#tech / frontend
#tech / ai
[!info] related notes
- 所属 MOC: AI Agent Application MOC
- 相关: Message State Management, Chat UI
Optimistic UI
一句话定义
Optimistic UI 是在等待后端响应前先在 UI 上展示预期结果的模式。在 AI 对话中,用户发送消息后立即显示在界面上,不需要等后端返回确认。
它解决什么问题
如果用户发送消息后要等后端确认才显示:
- 网络延迟导致 UI 卡顿
- 用户不确定消息是否发送成功
- 快速连续发送时体验差
Optimistic UI 让界面立即响应,后端异步确认。
核心原理
传统流程:
用户输入 → 发送请求 → 等待响应 → 显示消息
(延迟 200-500ms)
Optimistic 流程:
用户输入 → 立即显示消息 → 发送请求 → 后台确认/回滚
(延迟 0ms)
实现
function useChat() {
const [messages, setMessages] = useState([]);
const sendMessage = async (content: string) => {
// 1. 立即添加用户消息(乐观更新)
const tempId = `temp_${Date.now()}`;
setMessages(prev => [...prev, {
id: tempId,
role: 'user',
content,
status: 'sending', // 临时状态
}]);
// 2. 创建 assistant 消息占位
setMessages(prev => [...prev, {
id: `assistant_${tempId}`,
role: 'assistant',
content: '',
status: 'streaming',
}]);
// 3. 发送请求
try {
const response = await fetch('/api/chat', { ... });
// 成功:更新为正式 ID
setMessages(prev => prev.map(msg =>
msg.id === tempId
? { ...msg, id: response.messageId, status: 'sent' }
: msg
));
} catch (err) {
// 失败:标记为错误
setMessages(prev => prev.map(msg =>
msg.id === tempId
? { ...msg, status: 'error' }
: msg
));
}
};
return { messages, sendMessage };
}
常见设计模式
1. 临时 ID
乐观更新使用临时 ID,后端确认后替换为正式 ID。
2. 状态标记
sending → sent / error
3. 回滚机制
请求失败时回滚 UI 状态,显示错误提示。
常见坑
- 不做回滚: 请求失败后 UI 仍然显示已发送
- ID 不替换: 临时 ID 没有替换为正式 ID,后续操作引用错误
- 不做重试: 发送失败后没有重试机制
- 状态不一致: 多个乐观更新并发时状态冲突