十分钟介绍mobx与react

原文地址:https://mobxjs.github.io/mobx/getting-started.htmlhtml

写在前面:本人英语水平有限,主要是写给本身看的,如有哪位同窗看到了有问题的地方,请为我指出,很是感谢;react

mobx是一个比redux更好的状态管理包,代码量更少,思路更清晰,没有像redux那样复杂的reducer,action (ps: redux的做者也推荐mobx,某大大告诉个人,并无原话连接)git

1.mobx 反应流程github

 2.the core idearedux

  State 是每个应用程序的核心部分,而使用一个不合规范的 State 则是让你的应用充满 bug 和失控的不二法门,或者就是局部变量环绕,让你的 state 失去了同步。有不少框架试图解决这个问题,好比使用不可变的 state,可是这样以来又带来了新的问题,好比数据必须规格化,完整性约束失效等等。而且它变得不可能使用强大的概念,如原型。数组

  MobX 让整个事情又变简单了:它不容许产生失控的 state。它的理念也很简单:全部能够从 state 中派生的事物,都会自动的派生。网络

  从概念上讲,Mobx会像Excel 表格同样处理您的应用程序。架构

 

  • 首先,有一个 state,它能够是一个object,array,primitives等等任何组成你程序的部分。你能够把这个想象成你应用程序的“单元格”。
  • 而后就是 derivations,通常它是指能够从 state 中直接计算的来的结果。好比未完成的任务的数量,这个比较简单,也能够稍复杂一些好比渲染你的任务显示的html。它相似于你的应用程序中的“公式和图表”。
  • Reactions 和 derivations 很像,主要的区别在于 reactions 并不产生数据结果,而是自动完成一些任务,通常是和 I/O 相关的。他们保证了 DOM 和 网络请求会自动适时地出发。
  • 最后是 actions。Actions 指的是全部会改变 state 的事情,MobX 保证全部 actions 都会有对应的 derivations 和 reactions 相伴,保证同步。

2.A simple todo store...

  理论说的够多的了,看一个例子也许会更明白一些。咱们从一个简单的 todo 程序开始。app

   为了原创性,让咱们从一个很是简单的ToDoStore开始。下面是一个很是直接的TodoStore,它维护着一个todos的集合。没有MobX参与。框架

class TodoStore {
    todos = [];

    get completedTodosCount() {
        return this.todos.filter(
            todo => todo.completed === true
        ).length;
    }

    report() {
        if (this.todos.length === 0)
            return "<none>";
        return `Next todo: "${this.todos[0].task}". ` + 
            `Progress: ${this.completedTodosCount}/${this.todos.length}`; 
    }

    addTodo(task) {
        this.todos.push({ 
            task: task,
            completed: false,
            assignee: null
        });
    }
}

const todoStore = new TodoStore();
                        

  咱们刚刚建立了一个带有todos集合的todoStore实例。用一些对象填充todoStore。为了确保咱们看到咱们的更改的影响,咱们在每次更改后调用todoStore.report并记录它。

  请注意,报表有意老是只打印第一个任务。它使这个例子有点人工,但正如你将看到下面它很好地演示了MobX的依赖关系跟踪是动态的。

 ===》 

3.Becoming reactive

   到目前为止,这段代码没有什么特别之处。可是若是咱们能够再也不手动调用 report 方法,只声明咱们但愿在每次状态更改时调用它?咱们只须要在想要的地方修改这个 state,全部的汇报都自动来作。

   幸运的是,这正是MobX能够为你作的。自动执行彻底取决于状态的代码。这样咱们的报表功能就会自动更新,就像电子表格中的图表同样。为了实现这一点,TodoStore必须成为可观察的(observable),以便MobX能够跟踪全部正在进行的更改。让咱们改变类就足以实现它。

  同时,completedTodosCount 属性应该被自动派生。经过使用@observable和@computed装饰器,咱们能够在对象上引入observable属性:

class ObservableTodoStore {
    @observable todos = [];
    @observable pendingRequests = 0;

    constructor() {
        mobx.autorun(() => console.log(this.report));
    }

    @computed get completedTodosCount() {
        return this.todos.filter(
            todo => todo.completed === true
        ).length;
    }

    @computed get report() {
        if (this.todos.length === 0)
            return "<none>";
        return `Next todo: "${this.todos[0].task}". ` + 
            `Progress: ${this.completedTodosCount}/${this.todos.length}`; 
    }

    addTodo(task) {
        this.todos.push({ 
            task: task,
            completed: false,
            assignee: null
        });
    }
}


const observableTodoStore = new ObservableTodoStore();

 

   至此!咱们将一些属性标记为@observable,以指示MobX这些值能够随时间改变。计算用@computed来装饰,以识别这些能够从状态导出。

   pendingRequests和assignee属性到目前为止未使用,但将在本教程后面使用。为了简洁,本页上的全部示例都使用ES6,JSX和装饰器。但不要担忧,全部的装饰在MobX有一个ES5写法。

  在构造函数中,咱们建立了一个report()将其包装在mobx.autorun()。mobx.autorun()建立一个运行一次的reaction,而后每当在函数内部使用的任何可观察数据发生变化时,自动从新运行。由于report()用observable todos属性,因此它会在适当时打印报表。这在下一个列表中演示。只需按下运行按钮:

==>

   纯函数,对吧?report自动打印了,同步而且没有泄漏的中间值。若是你仔细查看运行结果的话,你会发现咱们的第四句语句没有产生输出,由于咱们修改了todos[1]的数据,而咱们在report中指明的数据,并无todos[1]的变化而发生变化。而第五句话修改了todos[0]的数据则输出了。这个例子很好的说明了,autorun不是简单的监视了todos,而是精确到了具体的一项。

 4.Making React reactive

   Ok, so far we made a silly report reactive. Time to build a reactive user interface around this very same store. React components are (despite their name) not reactive out of the box. The @observer decorator from the mobx-react package fixes that by wrapping the React component render method in autorun, automatically keeping your components in sync with the state. That is conceptually not different from what we did with the report before.

   好了,到目前为止咱们作了一个愚蠢的 report reactive。是时候用很是类似的store建立一个reactive了。React components(尽管他们的名字)没有反应开箱。

  mobx-react包中的@observer装饰器经过在mobx.autorun()包装React组件的render()方法来实现,自动保持组件与状态同步。这在概念上与咱们之前的报告没有什么不一样

   下面的清单定义了几个React组件。在那里惟一属于MobX的东西是@observer装饰器。这足以确保每一个组件在相关数据更改时单独从新render。您不须要再调用setState,也没必要了解如何使用须要配置的选择器或更高级的组件来(subscribe :redux中有 )订阅应用程序状态的适当部分。基本上,全部组件都变得聪明。然而,它们是以愚蠢的,声明性的方式定义的。

@observer
class TodoList extends React.Component {
  render() {
    const store = this.props.store; 
    return (
      <div>
        { store.report }
        <ul>
        { store.todos.map(
          (todo, idx) => <TodoView todo={ todo } key={ idx } />
        ) }
        </ul>
        { store.pendingRequests > 0 ? <marquee>Loading...</marquee> : null }
        <button onClick={ this.onNewTodo }>New Todo</button>
        <small> (double-click a todo to edit)</small>
        <RenderCounter />
      </div>
    );
  }

  onNewTodo = () => { 
    this.props.store.addTodo(prompt('Enter a new todo:','coffee plz')); 
  } 
}

@observer
class TodoView extends React.Component {
  render() {
    const todo = this.props.todo;
    return (
      <li onDoubleClick={ this.onRename }>
        <input 
          type='checkbox'
          checked={ todo.completed }
          onChange={ this.onToggleCompleted } 
        />
        { todo.task }
        { todo.assignee 
          ? <small>{ todo.assignee.name }</small> 
          : null
        }
        <RenderCounter />
      </li>
    ); 
  }

  onToggleCompleted = () => {
    const todo = this.props.todo;
    todo.completed = !todo.completed;
  }

  onRename = () => {
    const todo = this.props.todo;
    todo.task = prompt('Task name', todo.task) || todo.task; 
  } 
}

ReactDOM.render(
  <TodoList store={ observableTodoStore } />, 
  document.getElementById('reactjs-app')
);

  下一个清单很好地显示,咱们只须要改变咱们的数据,而不作任何其余事情。 MobX将自动从存储中的状态从新导出和更新用户界面的相关部分。

  运行结果:

 

5.Working with references

  到目前为止,咱们已经建立了observable对象(原型对象和plain对象),数组和基元(primitives)。你可能想知道,在MobX中如何处理引用?个人state是否容许造成图表?在上一个列表中,您可能已经注意到todos有一个assignee 属性。让咱们给他们一些值,经过引入另外一个“store”(它只是一个glorified数组)包含人,和分配给他们的任务。

   

 

  那么问题来了,observableTodoStore.todos原本就是@observable的,奈何有要再增长一个呢?

   答:大概由于改变的时候方便?

 

  We now have two independent stores. One with people and one with todos. To assign an assignee to a person from the people store, we just assigned a reference. These changes will be picked up automatically by the TodoView. With MobX there is no need to normalize data first and to write selectors to make sure our components will be updated. In fact, it doesn't even matter where the data is stored. As long as objects are made observable, MobX will be able to track them. Real JavaScript references will just work. MobX will track them automatically if they are relevant for a derivation. To test that, just try changing your name in the next input box (make sure you have pressed the above Run code button first!).

  咱们如今有两个独立的商店。一我的和一个todos。要从people store中分配一个person的代理,咱们只须要分配了一个参考。这些更改将由TodoView自动选取。使用MobX,没有必要首先规范化数据,而且编写选择器以确保咱们的组件将被更新。事实上,数据存储的位置甚至都不重要。只要对象是可观察的,MobX将可以跟踪它们。真正的JavaScript引用将正常工做。 MobX将自动跟踪它们,若是它们与派生相关。要测试,只需尝试在下一个输入框中更改您的名称(确保您已经按上面的Run代码按钮!)。

   

 

 

6.Asynchronous actions

   由于咱们的小Todo应用程序中的一切都是从状态派生而来的,因此当状态改变时它并不重要。这使得建立异步操做真的很简单。只需按下面的按钮(屡次)来模拟异步加载新的todo项:

   后面的代码真的很简单。咱们从更新存储属性pendingRequests开始,让UI反映当前的加载状态。一旦加载完成,咱们更新商店的todos并再次减小pendingRequests计数器。只需将此代码段与早期的TodoList定义进行比较,便可了解如何使用pendingRequests属性

 

7.Conclusion

   就这样!没有样板。只是一些UI组件中的简单的声明性组件,造成咱们的完整的UI。这些是彻底地,反应性地从咱们的state中获得。如今,您能够开始在本身的应用程序中使用mobx和mobx-react包。您到目前为止学到的东西的简短摘要:

  • 使用@observable装饰器或observable(obj or array)函数令对象能够被MobX追踪。
  • @computed装饰器能够用于建立能够从状态自动导出其值的函数。
  • 使用autorun运行依赖于某个可观察状态的函数。这对log,网络请求等颇有用.
  • 使用来自mobx-react包的@observer装饰器,使您的React组件真正被动。他们将自动和有效地更新。即便用于具备大量数据的大型复杂应用程序。

   (我这里是不行的)

  能够随意使用上面的可编辑代码块玩一段时间,以得到MobX对全部更改的反应的基本感受。例如,您能够向报告函数添加一条日志语句,以查看它被调用的时间。或者根本不显示报告,看看它如何影响TodoList的呈现。或仅在特定状况下显示...

 

8.MobX is not a state container

   人们常用MobX做为Redux的替代品。但请注意,MobX只是一个库来解决技术问题,而不是一个架构或甚至状态容器自己。在这个意义上,上面的例子是设计的,而且建议使用适当的工程实践,如在方法中封装逻辑,在商店或控制器等组织它们。或者,正如HackerNews上的某人所说:

  “MobX,它在其余地方被提到,但我不能不赞赏它。在MobX中编写意味着使用控制器/调度程序/操做/管理程序或另外一种形式的管理数据流返回到一个架构问题,您能够模式化您的应用程序的须要,而不是默认状况下须要的任何东西比一个Todo应用程序。

相关文章
相关标签/搜索