Mobx初探

  • 蘇格團隊
  • 做者:Demian

1、前言

本文是筆者在看了 frontendmaster 的狀態管理課程以後,對 mobx 進行的初步學習的總結。html

2、Mobx 簡介

mobx 是社區內使用的較爲常見的一種狀態管理庫,mobx 官網稱其vue

經過透明的函數響應式編程(transparently applying functional reactive programming - TFRP)使得狀態管理變得簡單和可擴展react

mobx 主要有如下幾個核心特性:git

  • Observable State(可觀察狀態)
  • Computed Values(計算屬性)
  • Reactions(反應,完成頁面渲染、日誌打印)
  • Actions(動做)

如下介紹將結合部分 mobx 代碼,代碼地址: 示例代碼github

詳細代碼以下:編程

// html
<div id="console" />;

// js
const { computed, observable, autorun } = mobx;

class Person {
  @observable firstName;
  @observable secondName;

  constructor(firstName, secondName) {
    this.firstName = firstName;
    this.secondName = secondName;
  }

  @computed get fullName() {
    return this.firstName + ' ' + this.secondName;
  }
}

const wdz = new Person('Demian', 'Wang');
const greet = observable.box('good morning! ');

const render = () => {
  document.getElementById('console').innerText = greet + wdz.fullName;
};
// 動態更新dom內容
autorun(render);
複製代碼

此時網頁 ui 爲:redux

1.Computed Values

首先介紹一下計算屬性。在上述代碼中 fullName 就是計算屬性。相信用過 vue 的對這個很熟悉。當咱們在命令行手動修改 wdz 的 firstName 時,wdz 的 fullName 會自動更新babel

此時網頁 ui 也發生了實時的變化:app

可見,computed 屬性能夠響應 observable 屬性的變化。frontend

值得一提的是,在 react 的 render 函數中,若是存在不少 props 的計算的話,可使用 get 語法的形式將這部分邏輯抽離:

get fullName() {
  return this.props.firstName + this.props.secondName;
}
render() {
  return <div>{this.fullName}</div>
}
複製代碼

這裏的 fullName 和可計算屬性相似,依據傳入的 props 屬性動態變化。

2.Observable State

經過在類屬性前加上@observable,爲該屬性添加了可觀察功能。

import { observable } from 'mobx';
class Person {
  @observable firstName;

  constructor(firstName) {
    this.firstName = firstName;
  }
}
複製代碼

使用裝飾器語法很簡潔的使得 name 擁有了可觀察的功能。

那麼 Observable 有什麼做用呢?

見如下代碼:

const greet = observable.box('good morning! ');
複製代碼

咱們爲 greet 返回一個 observable 包裝過的值,首先咱們試着直接改變 greet 的值

可是,此時網頁 ui 沒有實時變化:

可見,原始類型在包裝過以後, 直接改變引用值不能觸發頁面動態更新,感興趣的讀者能夠點擊上面的連接打印出 greet 的屬性,就能很直觀的認識到 observable 的做用。

如下是簡化版的 observable:

// 簡單的observable
const observable = value => {
  return {
    value,
    get() {
      console.log('get', this.value);
      return this.value;
    },
    set(newValue) {
      console.log('set', newValue);
      // 向全局通知該數據更新
      report(this.value, newValue);
      this.value = newValue;
    }
  };
};

// reactive代碼
eventEmitter.on('report', (oldValue, newValue) => {
  console.log(oldValue, '===>', newValue);
});

// 通知給全局
const report = (oldValue, newValue) => {
  eventEmitter.emit('report', oldValue, newValue);
};
複製代碼

主要是使用 value 值存儲原始類型,使用 get 獲取 value 值,使用 set 更新 value 值。值得注意的是,在更新數據之前,set 方法會根據必定的配置,選擇是否向全局發送更新事件,相應的一些 computed 的屬性會接收到該事件。

3.Reactions

const render = () => {
  document.getElementById('console').innerText = greet + wdz.fullName;
};
// 動態更新dom內容
autorun(render);
複製代碼

當 observable 數據變化後,頁面會自動更新 ui。

3、mobx 實戰-實現一個 todoList

注:因爲 create-react-app 建立的項目默認不能使用裝飾器語法,因此筆者暴力的 eject 並安裝了相應的 babel 配置。

如下是 todoList 的項目結構:

最終實現效果:

項目地址: todolist

當咱們使用 mobx 維護狀態時,store 不像 redux 那樣是全局惟一的,咱們能夠細粒度地維護一個個數據模型。在中小型的項目中,mobx 的 store 輕便簡潔,使用起來很順滑。

項目中用到的 mobx 特性:

1.observable

主要維護 todolist 的基本狀態:待辦列表 todolist、新建待辦的內容 itemContent 和當前篩選類型 filterType

2.computed

根據當前篩選器的類型,返回對應的 todoList。

3.reactions

篩選器狀態變化後,響應式地打印出當前篩選器的狀態。

4.actions

點擊篩選器後的狀態切換和異步事件。這裏須要使用 runInAction 包裝異步函數,這樣才能夠完成響應式的更新數據。

4、Mobx vs Redux

二者都是優秀的狀態管理工具,均可以幫助開發者完成業務開發。因此拋開業務場景談論工具優劣是無心義的,筆者這裏只是簡單列出二者的區別。

修改數據

中間件

5、總結

筆者只是介紹了 mobx 的冰山一角,其做爲一種響應式的狀態管理庫,在中小型項目中有着高效率的表現。響應式的寫法、細粒度的 store 管理都體現了 mobx 的靈活性。

相關文章
相關標籤/搜索