翻译君Mobx,Ten minute introduction to MobX and React

简要介绍:最近看了一下Mobx,然后有一篇入门教程是英文的,这里翻译一下并写写自己的心得体会。

原文地址:https://mobx.js.org/getting-started.html

一、Mobx的核心思想

(1)Mobx的核心思想概括:

贯穿mobx状态管理机的核心思想是使得state保持一致性,我是这么理解

的,任何来源于state的数据,显示都应该与state的改变保持一致性,换

句话说,只要state改变,那么显示的view层就会自动发生改变。

(2)Mobx中的数据流

这里写图片描述

简单来说,view层的渲染或者更新直接来源于state,而actions可以直接改变state,对比与redux的数据流,我们发现少了reducer这个过程,因此mobx较为简单易用。

–state,声明被监听的数据结构,这里的数据结构可以是对象,数组,原

始类型或者是引用类型,并且state是整个应用的数据来源”data cell”

–来源于state的衍生物,基础的衍生物是计算属性(computed),计算

属性可以来源于一些简单的值,或者是一些运算等等,换种话说,计算属

性可以是方程或者是你应用中的表格,用于展示数据。

–来源于state的另一个衍生物是反应(reaction),与计算属性不同的是

reaction不会返回一个结果值,它用于执行一些工程或者说函数,比如一

些I/O操作,或者网络请求等等。

–最后就是动作(action),动作是用于改变state的,mobx的特点是,保

证了通过action改变了action后,会自动的反应到衍生物reaction和

computed,从而达到一个自动更新View的目的。

二、 一个简单的 No MobX store

我们简单的来说一下没有采用mobx的store例子,从一个todo store看起:

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();

这里定义了一个TodoStore类,类的构造成员为todo数组,可以添加数组addTodo,report方法,可以输出数组的长度,以及数组中有多少个元素的completed为true。

下面来看手动执行这几个构造方法的过程:

todoStore.addTodo("read MobX tutorial");
console.log(todoStore.report());

todoStore.addTodo("try MobX");
console.log(todoStore.report());

todoStore.todos[0].completed = true;
console.log(todoStore.report());

todoStore.todos[1].task = "try MobX in own project";
console.log(todoStore.report());

todoStore.todos[0].task = "grok MobX tutorial";
console.log(todoStore.report());

执行的结果为:

Next todo: "read MobX tutorial". Progress: 0/1
Next todo: "read MobX tutorial". Progress: 0/2
Next todo: "read MobX tutorial". Progress: 1/2
Next todo: "read MobX tutorial". Progress: 1/2
Next todo: "grok MobX tutorial". Progress: 1/2

存在的问题:

就是每次添加完元素,或者改变了元素的completed属性之后,都必须手

动的执行todoStore.report()方法才能输出结果。也就是说不能自动的监

听成员属性todo数组的变化。

三、通过mobx使得todo store自动响应

我们看到了上述例子的缺陷就是不能自动执行响应,我们这里把todo数

组看成是数据源,而report()函数看成是响应函数,也就是我们需要实现

让state变动的时候自动执行响应,我们可以利用mobx。

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();

上述代码就实现了一个state改变后自动执行的ObservableTodoStore

类,这里我们通过mobx提供的observable装饰符,监听todos数据,

根据mobx提供的computed计算属性,这个计算属性会保证在todos观

测属性改变的时候自动执行。下面我们来看执行方法和结果。

执行方法:

observableTodoStore.addTodo("read MobX tutorial");
observableTodoStore.addTodo("try MobX");
observableTodoStore.todos[0].completed = true;
observableTodoStore.todos[1].task = "try MobX in own project";
observableTodoStore.todos[0].task = "grok MobX tutorial";

执行结果:

Next todo: "read MobX tutorial". Progress: 0/1
Next todo: "read MobX tutorial". Progress: 0/2
Next todo: "read MobX tutorial". Progress: 1/2
Next todo: "read MobX tutorial". Progress: 1/2
Next todo: "grok MobX tutorial". Progress: 1/2

我们发现了有趣的事情,通过mobx实现了监听和自执行之后,我们在添

加元素或者改变todos元素的值得时候,会自动的调用computed修饰的

函数,实现了state改变,自动执行computed的效果。

四、在react中利用mobx

在react中利用mobx本质,同上述的例子是一样的,只不过通过

observer修饰了react组件之后,render方法变成了一个监听函数,

一旦store发生改变,就会改重新去render,store通过react的context来

传递到所有子组件。实现代码如下:

@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')
);

改变store后的方法:

const store = observableTodoStore;
//observableTodoStore=new ObservableTodoStore();
store.todos[0].completed = !store.todos[0].completed;
store.todos[1].task = "Random todo " + Math.random();
store.todos.push({ task: "Find a fine cheese", completed: true });

因为render有todos属性,只要todos在外界也就是传入的store中发生改

变,都会重新render。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章