如何在mobx-state-tree模型中存储非MST类型(类实例)?
解决MST中存储SignalR HubConnection实例的问题
好问题!你碰到的这个报错本质是mobx-state-tree(MST)的模型字段有严格的类型要求——必须是MST原生类型或者自定义的MST兼容类型,而HubConnection是SignalR的普通类实例,不属于MST的类型体系,直接用肯定会触发错误。
能不能在MST模型中存储非MST类型?
当然可以!MST提供了多种方式来支持存储外部类实例,核心思路是要么把非MST类型包装成MST兼容的自定义类型,要么把实例放在MST的“非追踪”属性中。下面给你两种实用的解决方案:
方案1:用types.custom()定义自定义MST类型
这种方式让MST能识别并验证HubConnection实例,适合需要把实例纳入模型状态体系的场景:
import { HubConnection } from '@aspnet/signalr-client'; import { types } from 'mobx-state-tree'; // 自定义一个适配HubConnection的MST类型 const HubConnectionType = types.custom<HubConnection>({ name: 'HubConnection', // 验证传入值是否为HubConnection实例 isTargetType: (value) => value instanceof HubConnection, // 序列化逻辑:如果不需要把连接实例存入快照,直接返回null即可 serialize: () => null, // 反序列化逻辑:直接返回传入的实例(因为我们是手动创建的) deserialize: (value) => value }); // 在模型中使用这个自定义类型 const MyStore = types.model('MyStore', { connection: types.optional(HubConnectionType, new HubConnection('http://localhost:5000/myhub')) }) .actions(self => ({ // 初始化连接事件监听 initConnection() { self.connection.on('Someaction', async (res: any) => { // 这里可以处理事件,比如更新模型内的状态 // 例如:self.updateSomeState(res) }); }, // 启动连接并调用服务端方法 startConnection() { return self.connection.start().then(() => { self.connection.invoke('Someotheraction'); }); }, // 关闭连接 stopConnection() { return self.connection.stop(); } }));
方案2:用volatile属性存储实例
如果不需要把连接实例纳入MST的状态追踪和快照体系,用volatile属性更简单——它专门用来存放不需要被MST管理的外部实例:
import { HubConnection } from '@aspnet/signalr-client'; import { types } from 'mobx-state-tree'; const MyStore = types.model('MyStore', { // 这里放需要MST追踪的业务状态,比如连接状态:isConnected: types.boolean }) .volatile(self => ({ // 在这里存储HubConnection实例,MST不会对它做类型检查或序列化 connection: new HubConnection('http://localhost:5000/myhub') })) .actions(self => ({ initConnection() { self.connection.on('Someaction', async (res: any) => { // 处理事件,比如更新模型中的isConnected状态 }); }, startConnection() { return self.connection.start().then(() => { // 可以在这里更新模型状态,比如:self.isConnected = true self.connection.invoke('Someotheraction'); }); } }));
这类内容属于Mobx/MST的设计范畴吗?
完全属于!把外部服务实例(比如SignalR连接、API客户端、WebSocket等)的管理逻辑封装在MST模型中,让React组件只负责UI渲染和触发模型动作,这正是MST提倡的关注点分离原则。MST本身就提供了types.custom()和volatile这类工具来支持这种场景,所以你完全可以放心地这么做。
额外注意事项
- 使用
types.custom()时,要确保序列化逻辑不会报错——因为MST默认会生成模型快照,而HubConnection实例无法被序列化,所以在serialize方法返回null或者空对象即可。 - 如果需要追踪连接的状态(比如是否已连接、连接错误信息),建议把这些状态放在MST的普通模型字段中,在动作中更新,这样组件就能通过MST的状态变化自动重新渲染。
内容的提问来源于stack exchange,提问作者Soren
相关产品推荐
相关产品推荐

