在上一部分中,咱们研究了如何设置MobX状态树并使其可观察。 有了这个,下一步就是开始对变化做出反应。 坦率地说,这就是有趣的开始!javascript
MobX保证只要您的响应数据图发生变化,依赖于可观察属性的部分就会自动同步。 这意味着您如今能够专一于对变化作出反应并引发的反作用,而不是担忧数据同步。java
让咱们深刻研究一下能够引发反作用的各类方法。react
@action
做为入口点默认状况下,当您修改observable时,MobX将检测并保持其余依赖的可观察对象同步。 这是同步发生的。 可是,有时您可能但愿在同一方法中修改多个observable。 这可能会致使多个通知被触发,甚至可能会下降您的应用速度。segmentfault
更好的方法是action()
中包装要调用的方法。 这会在您的方法周围建立一个事务边界,而且全部受影响的observable
将在您执行操做后保持同步。 请注意,此延迟通知仅适用于当前函数范围中的observable
。 若是您具备修改更多可观察对象的异步操做,则必须将它们包装在runInAction()
中。异步
class Person { @observable firstName; @observable lastName; // 由于咱们在@action中包装了此方法,因此只有在changeName()成功执行后,fullName才会更改 @action changeName(first, last) { this.firstName = first; this.lastName = last; } @computed get fullName() { return `${this.firstName}, ${this.lastName}`; } } const p = new Person(); p.changeName('Pavan', 'Podila');
Actions
是改变Store的切入点。 经过使用Actions
,您能够将多个observable更新为原子操做。ide
尽量避免直接从外部操纵observable
并公开@action
方法为你作这个改变。 实际上,能够经过设置useStrict(true)
来强制执行此操做。
@autorun
触发反作用MobX确保可观察图形始终保持一致。 但若是这个世界只是关于可观察的东西,那就很差玩了。 咱们须要他们的同行:观察者使事情变得有趣。函数
实际上,UI是mobx store
的美化观察者。 使用mobx-react
,您将得到一个绑定库,使您的React组件能够观察存储并在存储更改时自动呈现。this
可是,UI不是系统中惟一的观察者。 您能够向store
添加更多观察者以执行各类有趣的事情。 一个很是基本的观察者多是一个控制台记录器,它只是在可观察的变化时将当前值记录到控制台。url
经过autorun
,咱们能够很是轻松地设置这些观察者。 最快的方法是提供autorun
功能。 MobX会自动跟踪您在此函数中使用的任何可观察对象。 每当它们改变时,你的功能都会从新执行(也就是自动运行)!spa
class Person { @observable firstName = 'None'; @observable lastName = 'None'; constructor() { // A simple console-logger autorun(()=>{ console.log(`Name changed: ${this.firstName}, ${this.lastName}`); }); // 这里会致使autorun()运行 this.firstName = 'Mob'; // autorun()再一次运行 this.lastName = 'X'; } } // Will log: Name changed: None, None // Will log: Name changed: Mob, None // Will log: Name changed: Mob, X
正如您在上面的日志中所看到的,自动运行将当即运行,而且每次跟踪的可观察量发生变化时也会运行。 若是您不想当即运行,而是仅在发生更改时运行,该怎么办? 请继续阅读。
reaction
触发反作用与autorun
相比,reaction
提供了更细粒度的控制。 首先,它们不会当即运行并等待对跟踪的可观察量的第一次更改。 API也与autorun
略有不一样。 在最简单的版本中,您提供两个输入参数:
reaction(()=> data, data => { /* side effect */})
第一个函数(跟踪函数 tracking function
)应该返回将用于跟踪的数据。 而后将该数据传递给第二个函数(效果函数 effect function
)。 不跟踪效果函数,您能够在此处使用其余可观察对象。
默认状况下,reaction
将不会在第一次运行,并将等待追踪函数的变动。 只有当tracking function
返回的数据发生变化时,才会执行反作用。 经过将原始自动运行分解为tracking function
+effect function
,您能够更好地控制实际致使反作用的内容。
import {reaction} from 'mobx'; class Router { @observable page = 'main'; setupNavigation() { reaction(()=>this.page, (page)=>{ switch(page) { case 'main': this.navigateToUrl('/'); break; case 'profile': this.navigateToUrl('/profile'); break; case 'admin': this.navigateToUrl('/admin'); break; } }); } navigateToUrl(url) { /* ... */ } }
在上面的示例中,我在加载“main”页面时不须要导航。 一个reaction
使用的完美案例。 仅当路由器的页面属性发生更改时,才会导航到特定URL。
以上是一个很是简单的路由器,具备固定的页面集。 您能够经过向URL添加页面地图来使其更具可扩展性。 使用这种方法,路由(使用URL更改)会成为更改Store某些属性的反作用。
when
触发一次性的反作用autorun
和reaction
是持续的反作用。 初始化应用程序时,您将建立此类反作用,并指望它们在应用程序的生命周期内运行。
我以前没有提到的一件事是这两个函数都返回一个处理器函数。 您能够随时调用该处理器函数并取消反作用。
const disposer = autorun(()=>{ /* side-effects based on tracked observables */ }); // .... At a later time disposer(); // Cancel the autorun
如今咱们构建的应用程序有各类用例。 您可能但愿某些反作用仅在您到达应用程序中的某个点时运行。 此外,您可能但愿这些反作用只运行一次,而后不再会运行。
让咱们举一个具体的例子:好比说,当用户到达应用程序中的某个里程碑时,您但愿向用户显示一条消息。 此里程碑仅对任何用户发生一次,所以您不但愿设置持续运行的反作用,如autorun
或reaction
。 如今是时候拿出when
这个API来完成这项工做了。
当拿出两个参数时,就像reaction
同样。 第一个(跟踪器函数)应该返回一个布尔值。 当这变为真时,它将运行效果函数,第二个参数为when
。 最棒的部分是它会在运行后自动处理反作用。 所以,无需跟踪处理器并手动调用它。
when(()=>this.reachedMilestone, ()=>{ this.showMessage({ title: 'Congratulations', message: 'You did it!' }); })
到目前为止,咱们已经看到了各类技术来跟踪对象图上的变化,并对这些变化作出反应。 MobX提升了抽象级别,以便咱们能够在更高级别进行思考,而没必要担忧跟踪和对变化作出反应的意外复杂性。
咱们如今有了一个基础,能够构建依赖于域模型更改的强大系统。 经过将域模型以外的全部内容视为反作用,咱们能够提供视觉反馈(UI)并执行许多其余活动,如监控,分析,日志记录等。