主题
React + AI 应用开发
React 多会话 AI Chat 如何隔离状态避免串线?
会话隔离不是给页面加一个 id,而是让请求、缓存、流事件和持久化都使用同一套归属键。
面试官想考什么
- 会话切换时旧流如何处理? 考察异步竞态。
- 缓存 key 怎么设计? 考察数据隔离与权限边界。
- 两个标签页同时生成怎么办? 考察跨页面同步。
- 为什么全局 messages 容易串线? 考察状态作用域。
一句话回答
text
我会以 tenantId、userId、conversationId、messageId 和 requestId 组成明确的归属链,所有缓存、事件处理和持久化都按 conversationId 分区,并通过版本校验、取消旧订阅和权限复核阻止旧流写入当前会话。面试回答详解
1. 归属模型
text
tenant/user -> conversation -> message -> generation attempt -> eventUI 当前选中的会话只是视图指针,不应成为流事件写入的依据。事件必须根据自身 conversationId 找到目标 store,再决定是否展示。
2. 缓存与状态
- 列表缓存 key:
["conversations", tenantId, userId] - 消息缓存 key:
["messages", tenantId, conversationId] - 生成任务 key:
["generation", conversationId, requestId]
服务端仍然必须做权限检查;前端 key 不是安全边界。切换会话时可以保留后台生成,但只能更新对应分区。
3. 切换竞态
为当前页面订阅保存 viewRevision。切换后旧订阅可以 abort,也可以继续后台运行;无论哪种策略,旧事件都不能依据闭包里的 currentConversationId 写入新会话。列表项使用稳定 key,不能用数组 index。
4. 多标签页
可用 BroadcastChannel 同步取消、完成和失效消息;服务端事件仍是权威来源。跨标签更新要带 revision,接收方只接受更高版本,并防止本标签广播再次回环。
5. 取舍
- 只允许一个活动生成:实现简单,适合成本敏感产品。
- 每会话并发生成:体验好,但要有配额、队列和资源上限。
- 全量刷新消息:简单可靠,但流式体验和网络成本较差。
- 局部事件更新:效率高,但协议和一致性复杂。
可直接背诵的 30 秒回答
text
多会话隔离的关键是让事件自己携带归属,而不是让回调读取当前选中的会话。缓存和 store 按 tenant、user、conversation 分区,消息更新再按 messageId 和 revision 校验。切换时取消或保留旧任务都可以,但旧流不能写入新会话;多标签页用 BroadcastChannel 做失效同步,权限始终由服务端复核。扩展知识
组件 key 的影响
消息行的 key 应是稳定的 messageId。切换会话时如果 key 不稳定,React 可能复用错误的本地输入、展开状态或动画状态。
面试官追问链
追问一:旧会话生成要不要自动取消?
- 考察点:产品与成本取舍。
- 回答方向:不是技术绝对答案;短问答可取消节省成本,长任务或后台任务可继续,但必须有配额和状态入口。
追问二:前端缓存泄露数据怎么办?
- 考察点:安全边界。
- 回答方向:服务端每次读取和流连接都鉴权;登出清理内存和持久缓存,跨租户 key 不复用,敏感内容不放长期本地存储。
追问三:如何处理两个客户端同时编辑同一条消息?
- 考察点:协作一致性。
- 回答方向:引入 revision/ETag,冲突时提示或合并;生成中的消息通常只允许服务端追加,人工编辑创建新版本。