解决模块隐式耦合的核心是明确状态归属、收敛通信路径:每个状态有唯一Owner模块,跨模块访问须通过契约接口;采用事件总线、依赖注入或URL传参实现显式通信;复杂业务状态抽取为组合式Context;以可隔离单元测试为解耦验收标准。

模块间相互调用状态,本质是状态归属不清晰、通信路径不收敛导致的隐式耦合。解决核心不是“禁止调用”,而是让状态有明确主人、通信可追溯、变更可预期。
状态必须有唯一归属模块
一个状态变量只能由一个模块负责初始化、读取和更新。例如用户登录态不能既在 AuthModule 里维护,又被 ProfileModule 直接修改。否则任意一方改逻辑都可能破坏另一方假设。
- 识别所有跨模块共享的状态(如 token、用户信息、全局加载态)
- 为每个状态指定唯一“Owner 模块”,其他模块只通过约定接口访问
- Owner 模块暴露只读 getter + 明确语义的 action(如 login()、logout()),禁止暴露原始 state 引用
模块通信走显式通道,禁用直接引用
模块 A 不应 import 模块 B 的内部函数或 store 实例来触发状态变更。所有跨模块影响必须经过定义好的契约接口。
- 使用事件总线(如 mitt、tiny-emitter)或发布-订阅模式,事件名带模块前缀(auth:logged-in、cart:item-added)
- 依赖注入方式:主容器(如 App 或 CoreModule)持有状态服务实例,按需注入到子模块,子模块只调用服务方法,不感知实现
- 路由参数或 URL 状态也可作为轻量通信载体(适合页面级模块切换时传递上下文)
用组合式状态管理替代分散 setState
当多个模块共同影响同一业务状态(如订单页涉及地址、商品、优惠券三个模块),不要让每个模块各自维护一份局部状态再拼接。应抽取为独立的状态组合器(Composable State)。
- 新建 OrderContext.ts,封装订单全流程所需状态与操作逻辑
- 各模块通过 useOrderContext() 获取统一 API,内部仍可封装自己的 UI 状态(如折叠面板开关),但业务状态只来自 Context
- 状态变更触发统一副作用(如保存草稿、校验连贯性),避免各模块各自响应导致逻辑碎片化
测试驱动解耦边界
能被单独测试的模块,大概率已具备清晰边界。把“能否不启动其他模块完成单元测试”作为解耦验收标准。
- 为每个模块编写隔离测试,mock 掉所有外部依赖(包括状态服务、事件总线)
- 验证模块只响应约定输入(props / event / service call),输出符合预期(DOM、emit、service 调用)
- 一旦某个测试需要启动 2 个以上模块才能跑通,说明边界模糊,应回溯重构通信方式

















