Skip to content

React + AI 应用开发

React 多会话 AI Chat 如何隔离状态避免串线?

会话隔离不是给页面加一个 id,而是让请求、缓存、流事件和持久化都使用同一套归属键。

适合阶段:资深前端 / 架构面试核心能力:状态归属 · 缓存键 · 竞态

面试官想考什么

  • 会话切换时旧流如何处理? 考察异步竞态。
  • 缓存 key 怎么设计? 考察数据隔离与权限边界。
  • 两个标签页同时生成怎么办? 考察跨页面同步。
  • 为什么全局 messages 容易串线? 考察状态作用域。

一句话回答

text
我会以 tenantId、userId、conversationId、messageId 和 requestId 组成明确的归属链,所有缓存、事件处理和持久化都按 conversationId 分区,并通过版本校验、取消旧订阅和权限复核阻止旧流写入当前会话。

面试回答详解

1. 归属模型

text
tenant/user -> conversation -> message -> generation attempt -> event

UI 当前选中的会话只是视图指针,不应成为流事件写入的依据。事件必须根据自身 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,冲突时提示或合并;生成中的消息通常只允许服务端追加,人工编辑创建新版本。

推荐阅读

基于 MIT 协议开源