服务与状态
import { createAppContext, createAppContextKey } from 'ds-ui'
DirectSurface UI 不限制业务状态管理方案。它提供的基础能力是上下文、组件状态、命令刷新和生命周期释放。复杂业务可以在这个基础上接入自己的 store、接口服务、缓存服务和审计服务。
状态分层
推荐把状态分成三类:
- 应用状态:登录用户、租户、主题、全局权限、工作台打开项。
- 页面状态:查询条件、选中行、编辑草稿、当前文档。
- 组件内部状态:hover、focus、selected、expanded、scroll offset。
应用状态通常挂在应用上下文。页面状态由页面对象持有或放入页面上下文。组件内部状态由组件自己管理,业务不要绕过组件 API 直接改内部字段。
上下注入示例
const currentRecordKey = createAppContextKey<{ id: string; title: string }>('currentRecord') const pageContext = createAppContext()pageContext.set(currentRecordKey, { id: 'record-001', title: '入院记录' }) const currentRecord = pageContext.require(currentRecordKey)currentRecord.title
这个示例只说明框架如何保存和读取上下文。真实业务对象由业务系统自己定义。
服务注入
服务适合放在应用级上下文或页面级上下文。全局通用服务放应用级,比如通知、权限、字典、API 客户端。跟某个页面强相关的服务放页面级,比如当前病历草稿服务、当前质控任务服务。
如果服务内部持有订阅、缓存或定时器,应通过可释放上下文注册,让页面关闭时自动清理。
状态刷新
业务状态改变后,通常需要做三件事:
- 更新页面状态或服务缓存。
- 更新组件输入属性。
- 触发命令状态重新求值。
组件的布局和绘制会由框架管线处理。业务不要在每个字段变化时强制全局刷新,应尽量只更新相关组件或相关页面。
避免全局单例污染
复杂系统里最常见的隐患是把当前患者、当前文档、当前选中行放成全局单例。这样会导致多 tab、多窗口和弹窗场景互相污染。
推荐规则:
- 当前登录用户可以是全局。
- 当前页面参数应该是页面级。
- 当前编辑对象应该是页面级。
- 当前选中行应该是组件或页面级。
- 临时弹窗参数应该是弹窗级。
只有生命周期和可见范围都相同的对象,才应该放到同一个上下文层级。