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

来源:互联网 发布:马氏链模型matlab编程 编辑:程序博客网 时间:2024/05/23 21:36

简要介绍:最近看了一下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/1Next todo: "read MobX tutorial". Progress: 0/2Next todo: "read MobX tutorial". Progress: 1/2Next todo: "read MobX tutorial". Progress: 1/2Next 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/1Next todo: "read MobX tutorial". Progress: 0/2Next todo: "read MobX tutorial". Progress: 1/2Next todo: "read MobX tutorial". Progress: 1/2Next todo: "grok MobX tutorial". Progress: 1/2

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

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

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

四、在react中利用mobx

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

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

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

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

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

原创粉丝点击