MobX State Tree如何无额外开销获取特定ID的引用列表/计数?
问题描述
我们有一个带标识符的模型:
const ReferableModel = types.model({ id: types.identifier(), })
还有数量不定、可引用该模型的其他模型,这些模型可处于状态树的任意位置:
const Model1 = types.model({ ref: types.maybe(types.reference(ReferableModel)), }) const Model2 = types.model({ ref: types.maybe(types.reference(ReferableModel)), }) // and so on
请问能否无额外开销地列出(或至少统计)引用特定标识符的模型?已知可以手动统计,但想了解是否存在开箱即用的方法(比如是否遗漏了types.refinement相关的文档内容)。
解答
MobX-State-Tree(MST)本身没有开箱即用的无额外开销方案来直接列出或统计引用特定标识符的模型实例,原因如下:
- MST的引用系统是单向设计:引用仅维护从引用者到被引用对象的指针,被引用对象不会自动追踪所有指向它的引用关系,默认状态树中不存在反向引用的记录。
types.refinement的作用是对类型进行校验和约束,无法实现引用追踪的功能。
如果想要实现引用追踪,无法完全避免运行时开销,但可以通过MST的生命周期钩子实现自动化的反向引用维护,将开销降到最低:
- 给
ReferableModel添加反向引用集合,用于存储所有引用它的实例 - 封装带追踪逻辑的引用类型,利用
onResolvedValueChange钩子自动更新反向引用集合
示例代码:
const ReferableModel = types.model({ id: types.identifier(), }) .views(self => ({ // 获取所有引用当前实例的对象 get references() { return Array.from(self._references.values()) }, // 统计引用数量 get referenceCount() { return self._references.size } })) .actions(self => ({ _addReference(ref) { self._references.add(ref) }, _removeReference(ref) { self._references.delete(ref) }, afterCreate() { // 用WeakSet存储,避免阻止对象被垃圾回收 self._references = new WeakSet() } })) // 封装带反向追踪的引用类型 const trackedReference = (targetType) => { return types.reference(targetType, { onResolvedValueChange: function(newValue, oldValue) { // 移除旧引用的反向关联 if (oldValue) { oldValue._removeReference(this) } // 添加新引用的反向关联 if (newValue) { newValue._addReference(this) } } }) } // 使用封装后的引用类型定义模型 const Model1 = types.model({ ref: types.maybe(trackedReference(ReferableModel)), }) const Model2 = types.model({ ref: types.maybe(trackedReference(ReferableModel)), })
这种方式的优势是:
- 无需手动在每个引用模型中编写统计逻辑,所有追踪逻辑都封装在引用类型和被引用模型中
- 使用
WeakSet存储反向引用,不会造成内存泄漏 - 开销仅来自钩子函数的执行,属于实现该功能的必要成本
总结:如果要求完全无额外开销,MST没有对应的开箱即用方法;如果可以接受微小的自动化开销,上述方案是比较优雅的实现方式。
内容的提问来源于stack exchange,提问作者Limbo
相关产品推荐
相关产品推荐

