状态管理
React Context、Store 与观察者模式
状态管理系统使用 React Context + Store 模式,集中管理应用状态。AppState 是核心,包含消息、工具状态、UI 状态、设置等。变更通过观察者模式通知所有订阅者。
核心要点
设计亮点
Object.is() 一招鲜吃遍天
React 判断要不要重新渲染时,不会深度比较两个对象的每个字段。它只用 Object.is() 比较引用——是同一个对象吗?因为 Claude Code 使用不可变更新(每次修改都创建新对象),没被改过的部分引用不变,React 立即知道'这部分没变,跳过'。整个判断过程几乎零成本。
所有副作用走一个漏斗
onChangeAppState 是 Claude Code 中唯一的副作用出口。需要在状态变更时写文件?注册到 onChangeAppState。需要发送通知?也注册到 onChangeAppState。这种单一出口设计让副作用变得可追踪、可调试。如果出了问题,只需要查看 onChangeAppState 的注册列表,而不是在整个代码库中搜索。
模块架构图
state/AppState.tsx500 LOC中央 React Context
state/AppStateStore.ts400 LOC持久化 Store
state/store.ts300 LOCRedux-like Store
state/onChangeAppState.ts200 LOC变更观察者
state/selectors.ts300 LOC状态选择器
关键代码
深入解析
AppState 是 Claude Code 的单一数据源,所有 UI 组件从中读取状态。它是一个巨大的 React Context,包含消息、工具状态、UI 状态、设置、子代理状态等所有运行时数据。
不可变更新确保了状态变更的可追踪性和 React 渲染的正确性。每次 setAppState 调用都创建一个新的状态对象,而不是修改现有对象。
观察者模式允许非 React 代码(如服务层、Bridge 通信层)响应状态变更。onChangeAppState 是唯一的副作用出口——所有需要在状态变更时触发的操作都注册在这里。
Selector 模式使用 useSyncExternalStore 实现精确订阅:组件只在自己关心的状态片段变化时重新渲染,而不是每次 AppState 变化都渲染。
Object.is() 比较是 React 判断是否需要重渲染的核心。因为使用不可变更新,如果某个状态片段没变,它的引用就不变,Object.is() 返回 true,React 跳过渲染——零成本判断。
AppStateStore 将关键状态持久化到磁盘(JSON 文件),确保 Claude Code 意外退出后能恢复会话状态。
终端 UI 使用 React + Ink 框架渲染——是的,Claude Code 的终端界面是用 React 写的,所以状态管理自然采用了 React 的模式。