首页/状态管理

状态管理

React Context、Store 与观察者模式

状态管理系统使用 React Context + Store 模式,集中管理应用状态。AppState 是核心,包含消息、工具状态、UI 状态、设置等。变更通过观察者模式通知所有订阅者。

核心要点

AppState — 中央 React Context
AppStateStore — 持久化 Store
onChangeAppState — 观察者模式
不可变更新 — setAppState 回调
Selector 模式 — 精确订阅状态片段

设计亮点

Object.is() 一招鲜吃遍天

就像你看快递箱子——箱子没换过就不用打开检查里面的东西有没有变

React 判断要不要重新渲染时,不会深度比较两个对象的每个字段。它只用 Object.is() 比较引用——是同一个对象吗?因为 Claude Code 使用不可变更新(每次修改都创建新对象),没被改过的部分引用不变,React 立即知道'这部分没变,跳过'。整个判断过程几乎零成本。

// 不可变更新的威力
const prev = { messages: [...], ui: { loading: true } }
const next = { ...prev, ui: { loading: false } }
// next.messages === prev.messages → true (引用没变)
// Object.is(next.messages, prev.messages) → true
// → React 跳过所有只依赖 messages 的组件

所有副作用走一个漏斗

就像公司的所有对外支出都必须经过财务部——不允许任何部门自己偷偷花钱

onChangeAppState 是 Claude Code 中唯一的副作用出口。需要在状态变更时写文件?注册到 onChangeAppState。需要发送通知?也注册到 onChangeAppState。这种单一出口设计让副作用变得可追踪、可调试。如果出了问题,只需要查看 onChangeAppState 的注册列表,而不是在整个代码库中搜索。

模块架构图

加载架构图...
核心文件
state/AppState.tsx500 LOC

中央 React Context

state/AppStateStore.ts400 LOC

持久化 Store

state/store.ts300 LOC

Redux-like Store

state/onChangeAppState.ts200 LOC

变更观察者

state/selectors.ts300 LOC

状态选择器

数据流程
1
状态变更
用户操作或工具执行
2
setAppState
不可变更新函数
3
通知观察者
触发所有订阅回调
4
重新渲染
UI 组件更新
5
持久化
Store 写入磁盘

关键代码

加载代码...

深入解析

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 的模式。