class FilterCriteria {
@observable filter = new Map();
}
let criteria = new FilterCriteria ();
// setting up a reaction when something in the filter changes
// (property added, removed, or changed)
reaction(()=>criteria.filter, data => console.log(data.toJSON()));
criteria.filter.set('name', 'John'); // setting a new property.
我希望上面的代码能打印出{ 'name': 'John' }
,但似乎反应没有运行。
我怀疑我以错误的方式设置了反应。每当添加新键,删除现有键或更改键值时,我都想做出反应。我在编译时不知道键或值。
我应该怎么做?
我将代码更改为
class FilterCriteria {
@observable filter = new Map();
@computed get json(){ return this.filter.toJSON(); }
}
...
reaction(()=>criteria.json, data => console.log(data));
,现在看来可以正常工作。每当我在地图中添加,删除或更改值时,都会执行反应副作用。
所以问题是,为什么反应在第二个示例中执行而在第一个示例中没有执行?
我再次更改了代码。我恢复到几乎第一个版本,但是这次而不是对criteria.filter
做出反应并记录data.toJSON()
,而是对criteria.filter.toJSON()
做出反应,并登录data
(toJSON从副作用中移出了到所观察的值)。这次反应正常进行。
class FilterCriteria {
@observable filter = new Map();
}
reaction(()=>criteria.filter.toJSON(), data => console.log(data));
再次,我不明白为什么。如果criteria.filter
本身不是可观察的,那么当 inside 条件.filter发生变化时,如何重新评估监视的表达式?
根据MobX文档,mobx在执行跟踪函数期间对读取的现有可观察属性做出反应。
当可观察属性更改时,会执行反应副作用。在我的示例中,当对criteria.filter
做出反应时,此处读取的observable属性为filter
,但过滤器本身从未更改。总是同一张地图。过滤器的属性会发生变化。因此,永远不会对criteria.filter
进行反应。
但是当我对criteria.filter.toJSON()
或mobx.toJS(criteria.filter)
做出反应时,该反应已正确执行。
那为什么呢? criteria.filter
不变,并且toJSON
不是可观察的属性。它是一个功能。 mobx.toJS
也是一样。似乎这里没有读取任何属性。但这是不正确的。正如文档所述(但不是很强调),执行toJSON或mobx.toJS时确实会读取criteria.filter的属性,因为这两个函数都创建了地图的深层克隆(因此遍历每个属性)。
现在,在开始时,地图不包含任何属性。那么,如何跟踪新添加的属性,因为开始跟踪时它们不存在(无法读取)?这是地图的功能。地图还为尚不存在的属性提供了可观察性。
在MobX 5中,您也可以跟踪可观察的对象的不存在属性(不是类实例),只要它们被observable或observable.object实例化。类实例不支持此功能。
答案 0 :(得分:1)
在mobx中,当您要观察可观察到的变化时,有两个选择。 reaction
和observe
。 Reaction
允许您指定何时可观察的特定方面发生更改时要调用某些函数。这可能是对数组长度,键,属性或其他任何东西的更改。 observe
会在可观察对象发生更改时触发一些功能。
我怀疑未触发您的反应的原因是由于第一个功能。 () => criteria.filter
。添加/删除键或更改值时,不会触发此操作。相反,它将在filter
实际更改时被触发。而且由于filter
实际上是对地图的引用,所以即使地图本身发生变化,它也永远不会改变。
以下是一些例子来说明我的观点:
如果要在添加或删除键时触发反应,则可能希望函数为:
() => criteria.filter.keys()
添加或删除键后,此功能的结果将有所不同。同样,如果您想在修改值时触发响应,则应执行以下操作:
() => criteria.filter.values()
因此,这两个组合应该是您侦听键/值更改所需要的。或者,您可以使用observe
,它会在每次更改时触发,并要求您检查已更改的内容,以确保满足特定条件以保证调用函数(即键/值更改)
更新:这是一个说明问题的示例
@observable map = new Map();
让我们说在内存中map的值为5。因此,当您检查map === map
时,它等效于5 === 5
并将计算为true。
现在,查看您发布的第一个代码段:
reaction(() => map, data => console.log(map.toJSON()));
每次添加/删除键或更改值时,第一个功能将运行。结果将是5,因为这就是我们在本例中所说的内存中的值。它会说:旧值是5,新值是5,所以没有变化。因此,该反应将不会运行第二个功能。
现在是第二个片段:
reaction(() => map.toJSON(), data => console.log(data));
首先,该函数的结果将为:{}
,因为Map为空。现在让我们添加一个密钥:
map.set(1, 'some value');
现在,第一个函数的结果将是:
{"1": "some value"}
很明显,此值与{}
不同,因此发生了某些变化,并调用了反应的第二个功能。