基於Mobx的多頁面小程序的全局共享狀態管理實踐

what

  • 名字很長很繞靠口,總的來講,本文是對開發小程序過程當中使用mobx的一個總結。前端

  • 狀態管理,相比你們也很熟悉,顧名思義,是對前端頁面繁複的狀態進行管理,在此,我也不過多贅述。vue

  • 因此雖然是是用在小程序上,不過我想對於WebApp的狀態管理,也有這麼一丟丟啓發。react

why

  • 爲何要進行狀態管理?
    如今的小程序儼然是Hybrid App,又像是PWA,但固然也是一個WebApp,更不用說他的語法和vue略微有這麼一丟丟類似。有reactvue的實踐在前,因此對於小程序上那麼多的頁面狀態和數據緩存,勢必也要引入一個狀態管理工具git

  • 爲何是mobx
    方便,快捷,學習成本低,固然也是仁者見仁智者見智github

how

  1. 在小程序中引入mobx
    在這裏我使用了wechat-weapp-mobx這個庫。在./libs目錄下放入mobx.jsobserver.js這兩個庫,同時在./store目錄下新建store.js用於存放全局狀態。小程序

  2. 創建store
    因爲小程序中不支持@decorate裝飾器,因此採用了extendObservable的寫法。另外,小程序支持import語法和require語法。我比較喜歡import語法,大家呢?我認爲在action中不應寫入複雜邏輯代碼,保持簡潔性和可複用性,大家怎麼看緩存

    // store.js
    // 引入必須的庫
    const mobx = require('../libs/mobx');
    const extendObservable = require('../libs/mobx').extendObservable;
    const computed = require('../libs/mobx').computed;
    const toJS = require('../libs/mobx').toJS;
    
    let store = function () {
      extendObservable(this, {
    
        // observable data
        players: [],
    
        // computed data
        get count() {
          return this.players.length;
        }
      });
    
      // action
      this.addPlayer = name => {
        let len = this.count;    //此處調用computed data
        let id = len === 0 ? 1 : this.players[len - 1].id + 1;
        this.players.push(new player(name, id));
      }
    }
    
    export default store;
  3. 全局引入store
    衆所周知,使用mobxstore要使用new store(),若是咱們想全局調用,勢必不可能在每一個頁面都new一個sotre,由於這樣的話每一個頁面的store都是一個全新的store。在這裏,我在app.js裏引入store,並掛載在全局變量globalData下。另外,小程序中不支持路徑的省略。網絡

    //app.js
    const observer = require('./libs/observer').observer;
    import store from './stores/index';  // 小程序中不支持省略調用
    
    App(observer({
      onLaunch: function () {
      },
      globalData: {
        store: new store()
      }
    }))
  4. 在pages裏調用全局的store
    能夠同時使用內置的data進行雙向綁定哦app

    // index.js
    const observer = require('../../libs/observer').observer;
    
    let app = getApp();
    Page(observer({
      data: {
        mes: 'hello jim green'
      },
      props: {
        store: app.globalData.store
      },
    }))
  5. 在頁面中調用storeide

    <view class="players-list">
      <view class="players-item" wx:for="{{props.store.players}}" wx:key="{{item.id}}">    // 調用observable data
        <text class="players">{{item.id}}:{{item.name}}</text>
      </view>
      <view>{{props.sotre.count}}</view>    //  調用computed data
    </view>
  6. 更新多個頁面的store
    問題來了,這個時候,多個頁面的store仍是獨立的,如何所有更新呢?答案就是在onShowonHide或者onUnload這三個生命週期函數中跟新全局的store

    onShow: function() {    // 顯示時更新本頁面store
      this.props.store = app.globalData.store
    },
    onHide: function() {   // 隱藏時更新全局store
      app.globalData.store = this.props.store;
    },
    onUnload: function() {    // 頁面跳轉返回時更新全局store
      app.globalData.store = this.props.store;
    },
  7. store和localStorage的長效存儲
    考慮到網絡還有程序崩潰的問題,我將store存儲在localStorage中以便恢復,我在index.jsonLoad中調用get storage,在onHideset storage。因爲toJS方法返回了一個不支持[Symbol.iterator]()的對象,因此在store裏進行了以下設置

    // index.js
    onLoad: function () {
      let store = wx.getStorageSync('store');
      if(store) {
        this.props.store.formStorageToStore(store);
      }
    },
    onHide: function () {
      
      let store =this.props.store.currentStore;
      wx.setStorageSync('store', store)
    },
    
    // store.js
      get currentStore() {
        let {players,games,currentGame,hidden,filter} = toJS(this);
        return {players,games,currentGame,hidden,filter};
      }
      this.formStorageToStore = ({players,games,currentGame,hidden,filter}) => {
        this.players = players;
        this.games = games;
        this.currentGame = currentGame;
        this.hidden = hidden;
        this.filter = filter;
      }

others

講點其餘

  • 本項目的示例小程序地址weapp-bmscore,歡迎各位老鐵點個關注666

相關文章
相關標籤/搜索