翻譯君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。

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