高效的Mobx模式(Part 2 - 掌握数据变动方法)

在上一部分中,咱们研究了如何设置MobX状态树并使其可观察。 有了这个,下一步就是开始对变化做出反应。 坦率地说,这就是有趣的开始!javascript

MobX保证只要您的响应数据图发生变化,依赖于可观察属性的部分就会自动同步。 这意味着您如今能够专一于对变化作出反应并引发的反作用,而不是担忧数据同步。java

让咱们深刻研究一下能够引发反作用的各类方法。react

使用@action做为入口点

默认状况下,当您修改observable时,MobX将检测并保持其余依赖的可观察对象同步。 这是同步发生的。 可是,有时您可能但愿在同一方法中修改多个observable。 这可能会致使多个通知被触发,甚至可能会下降您的应用速度。
actionsegmentfault

更好的方法是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触发一次性的反作用

autorunreaction是持续的反作用。 初始化应用程序时,您将建立此类反作用,并指望它们在应用程序的生命周期内运行。

我以前没有提到的一件事是这两个函数都返回一个处理器函数。 您能够随时调用该处理器函数并取消反作用。

const disposer = autorun(()=>{ 
    /* side-effects based on tracked observables */ 
});

// .... At a later time
disposer(); // Cancel the autorun

如今咱们构建的应用程序有各类用例。 您可能但愿某些反作用仅在您到达应用程序中的某个点时运行。 此外,您可能但愿这些反作用只运行一次,而后不再会运行。

让咱们举一个具体的例子:好比说,当用户到达应用程序中的某个里程碑时,您但愿向用户显示一条消息。 此里程碑仅对任何用户发生一次,所以您不但愿设置持续运行的反作用,如autorunreaction。 如今是时候拿出when 这个API来完成这项工做了。

当拿出两个参数时,就像reaction同样。 第一个(跟踪器函数)应该返回一个布尔值。 当这变为真时,它将运行效果函数,第二个参数为when。 最棒的部分是它会在运行后自动处理反作用。 所以,无需跟踪处理器并手动调用它。

when(()=>this.reachedMilestone, ()=>{
    this.showMessage({ 
        title: 'Congratulations', 
        message: 'You did it!'
    });
})


到目前为止,咱们已经看到了各类技术来跟踪对象图上的变化,并对这些变化作出反应。 MobX提升了抽象级别,以便咱们能够在更高级别进行思考,而没必要担忧跟踪和对变化作出反应的意外复杂性。

咱们如今有了一个基础,能够构建依赖于域模型更改的强大系统。 经过将域模型以外的全部内容视为反作用,咱们能够提供视觉反馈(UI)并执行许多其余活动,如监控,分析,日志记录等。

相关文章
相关标签/搜索