Skip to content

状态管理

定义应用状态管理架构规范


状态分类

三类状态

类型特点来源持久化示例
客户端状态本地产生用户操作钱包列表、偏好设置
服务端状态远程获取API/链缓存余额、交易历史
临时状态短期存在交互表单数据、UI 状态

状态层次

┌──────────────────────────────────────────┐
│            Temporary State               │
│         (表单级,组件生命周期内)            │
├──────────────────────────────────────────┤
│            Server State                  │
│          (应用级,自动缓存同步)             │
├──────────────────────────────────────────┤
│            Client State                  │
│          (应用级,持久化到本地)             │
└──────────────────────────────────────────┘

客户端状态规范

Store 定义

每个 Store MUST 包含:

Store<T> {
  // 状态
  state: T
  
  // 读取
  getState(): T
  subscribe(listener: (state: T) => void): Unsubscribe
  
  // 更新
  setState(updater: (prev: T) => T): void
}

钱包状态 (WalletStore)

字段类型持久化说明
walletsWallet[]钱包列表
currentWalletIdstring当前钱包 ID
selectedChainChainId当前选中链

偏好状态 (PreferencesStore)

字段类型持久化说明
languageLanguageCode界面语言
currencyCurrencyCode显示货币
theme'light' | 'dark' | 'system'主题模式
biometricEnabledboolean生物识别开关

UI 状态 (UIStore)

字段类型持久化说明
activeSheetSheetType当前弹窗
toastQueueToast[]Toast 队列
isLoadingboolean全局加载状态

地址簿状态 (AddressBookStore)

字段类型持久化说明
contactsContact[]联系人列表
isInitializedboolean是否已初始化

Contact 结构:

字段类型说明
idstring唯一 ID
namestring联系人名称
avatarstring?头像(avatar: 协议)
addressesContactAddress[]地址列表(最多 3 个)
memostring?私有备注
createdAtnumber创建时间
updatedAtnumber更新时间

ContactAddress 结构:

字段类型说明
idstring唯一 ID
addressstring区块链地址
labelstring?自定义标签(最多 10 字符)
isDefaultboolean?是否默认地址

服务端状态规范

缓存策略

数据类型缓存时长刷新策略
余额30 秒自动轮询 60s
交易历史1 分钟新交易时刷新
Token 元数据1 小时按需刷新
汇率5 分钟自动轮询
链配置24 小时手动刷新

查询键规范

查询键 MUST 遵循以下命名规则:

[domain, action, ...params]

示例:
['wallet', 'balances', address, chainId]
['transaction', 'history', address]
['token', 'metadata', tokenId]
['exchange', 'rates', baseCurrency]

查询状态

状态说明
idle未开始
loading加载中(首次)
success成功
error失败
fetching后台刷新中

状态操作规范

Action 定义

每个状态域 SHOULD 定义对应的 Actions:

WalletActions {
  addWallet(wallet: Wallet): void
  removeWallet(walletId: string): void
  updateWallet(walletId: string, updates: Partial<Wallet>): void
  setCurrentWallet(walletId: string): void
  setSelectedChain(chain: ChainId): void
}

Mutation 规范

服务端状态变更 MUST 通过 Mutation:

Mutation<TParams, TResult> {
  // 执行变更
  mutate(params: TParams): Promise<TResult>
  
  // 状态
  isPending: boolean
  isSuccess: boolean
  isError: boolean
  error: Error | null
  
  // 回调
  onSuccess?: (result: TResult) => void
  onError?: (error: Error) => void
  onSettled?: () => void
}

缓存失效

变更成功后 MUST 使相关缓存失效:

操作失效的缓存
转账发送方余额、接收方余额、交易历史
创建钱包钱包列表
质押/解质押余额、质押状态

状态持久化规范

存储键命名

bfm_{domain}_{version}

示例:
bfm_wallets_v1
bfm_preferences_v1
bfm_cache_v1

持久化策略

状态存储位置加密
钱包列表安全存储
用户偏好本地存储
查询缓存本地存储

版本迁移

  • MUST 在存储数据中包含版本号
  • MUST 支持旧版本数据迁移
  • SHOULD 在迁移失败时保留原数据
迁移流程:
读取存储数据


检查版本号

    ├── 当前版本 ──► 直接使用

    └── 旧版本 ──► 执行迁移

                    ├── 成功 ──► 保存新版本

                    └── 失败 ──► 使用默认值 + 报告错误

状态订阅规范

细粒度订阅

  • MUST 只订阅组件需要的状态片段
  • MUST NOT 订阅整个 Store 状态
  • SHOULD 使用选择器(Selector)提取状态

选择器规范

Selector<TState, TResult> = (state: TState) => TResult

示例:
// ✓ 好:细粒度选择
const currentWallet = useSelector(state => state.wallets.find(
  w => w.id === state.currentWalletId
))

// ✗ 差:订阅全部状态
const allState = useSelector(state => state)

派生状态

派生状态 SHOULD 通过选择器计算:

派生状态依赖计算
当前钱包wallets, currentWalletIdwallets.find(w => w.id === currentWalletId)
当前地址currentWallet, selectedChaincurrentWallet.addresses[selectedChain]
总资产balances, exchangeRatessum(balances * rates)

乐观更新规范

适用场景

操作乐观更新原因
切换钱包本地操作,必定成功
修改昵称失败概率低
转账需等待链上确认
删除钱包不可逆操作

乐观更新流程

用户操作


立即更新 UI(乐观)


发送请求

    ├── 成功 ──► 保持状态

    └── 失败 ──► 回滚状态 + 显示错误

错误处理规范

查询错误

  • MUST 显示错误状态
  • MUST 提供重试机制
  • SHOULD 显示缓存数据(如有)
  • SHOULD 自动重试网络错误

变更错误

  • MUST 显示错误消息
  • MUST 回滚乐观更新
  • SHOULD 保留用户输入
  • MAY 提供错误详情查看

本章小结

  • 状态分为客户端、服务端、临时三类
  • 客户端状态需持久化到本地
  • 服务端状态需合理配置缓存
  • 细粒度订阅避免过度渲染
  • 支持乐观更新提升体验
  • 版本迁移确保数据兼容

Released under the MIT License.