微信小程序中實(shí)現(xiàn)狀態(tài)管理

出發(fā)點(diǎn):之前起點(diǎn)小程序嘗試mpvue的一個(gè)重要原因就是mpvue支持狀態(tài)管理,雖然現(xiàn)在wepy也支持了redux函匕,但是其性能不是非常理想伐谈,且看到issue里面還是提了很多的bug纲菌,所以還是想著用原生來擼一個(gè)簡單夠用的。

Pub/Sub模式(發(fā)布/訂閱模式)

狀態(tài)管理中非常重要的點(diǎn)就是發(fā)布/訂閱模式逮京,發(fā)布/訂閱模式的原理非常簡單,一邊發(fā)布束莫,一邊訂閱懒棉。訂閱者在事件中心注冊具名事件和回調(diào)函數(shù),發(fā)布者通知事件中心執(zhí)行所有同名的回調(diào)函數(shù)览绿。

訂閱者 ---- 注冊事件 ----> 事件中心 <---- 通知 ---- 訂閱者

事件中心(pubsub.js)

既然需要提供事件注冊(訂閱)的功能策严,那么必然需要一個(gè)地方來存放所有的事件,同一個(gè)事件名可以有多個(gè)回調(diào)饿敲,那么顯然數(shù)據(jù)結(jié)構(gòu)如下:

{
  'fn_name': [fn1, fn2, fn3...],
  ...
}

所以事件中心的雛型如下:

export default class PubSub {
  constructor() {
    // events里存放的是所有的具名事件
    this.events = {};
  }

  //  提供訂閱功能
  subscribe(event, callback) {
    ...
  }

  // 提供發(fā)布功能
  publish(event, data) {
    ...
  }
}

訂閱功能:在具名事件的回調(diào)數(shù)組中推入了一個(gè)新的回調(diào)妻导,接受一個(gè)事件名和回調(diào)函數(shù)。

subscribe(event, callback) {
  let self = this;

  if(!self.events.hasOwnProperty(event)) {
    self.events[event] = [];
  }
  // 沒有做去重
  return self.events[event].push(callback);
}

發(fā)布功能:調(diào)用對應(yīng)事件名的所有回調(diào)函數(shù)怀各,參數(shù)為事件名和回調(diào)參數(shù)倔韭。

publish(event, data = {}) {

  let self = this;

  if(!self.events.hasOwnProperty(event)) {
    return [];
  }

  return self.events[event].map(callback => callback(data));
}

Store對象(store.js)

該對象主要用于存儲(chǔ)共享數(shù)據(jù),當(dāng)數(shù)據(jù)被更新時(shí)觸發(fā) stageChange 事件瓢对。

import PubSub from '../lib/pubsub.js';
export default class Store {
  constructor(params) {
    let self = this;
    self.actions = {}; // 存儲(chǔ)異步方法
    self.mutations = {}; // 存儲(chǔ)同步方法
    self.state = {}; // 共享數(shù)據(jù)
    self.status = 'resting';    // 防止手動(dòng)更新
    self.events = new PubSub();

    // 參數(shù)可以傳入初始的actions和mutations
    if(params.hasOwnProperty('actions')) {
      self.actions = params.actions;
    }

    if(params.hasOwnProperty('mutations')) {
      self.mutations = params.mutations;
    }

    // Proxy:es6的方法寿酌,起到攔截的作用
    self.state = new Proxy((params.state || {}), {
      set: function(state, key, value) {

        state[key] = value;

        console.log(`stateChange: ${key}: ${value}`);

        self.events.publish('stateChange', self.state);

        // 防止手動(dòng)更新
        if(self.status !== 'mutation') {
          console.warn(`You should use a mutation to set ${key}`);
        }

        self.status = 'resting';

        return true;
      }
    });
  }

  dispatch(actionKey, payload) { ... }

  commit(mutaionKey, payload) { ... }
}

dispatch:調(diào)用 actions,可以執(zhí)行一些異步的操作硕蛹,然后調(diào)用commit

dispatch(actionKey, payload) {

  let self = this;

  if(typeof self.actions[actionKey] !== 'function') {
    console.error(`Action "${actionKey} doesn't exist.`);
    return false;
  }

  console.groupCollapsed(`ACTION: ${actionKey}`);

  self.status = 'action';

  self.actions[actionKey](self, payload);

  console.groupEnd();

  return true;
}

commit:調(diào)用mutations

commit(mutationKey, payload) {
    let self = this;

    if(typeof self.mutations[mutationKey] !== 'function') {
    console.log(`Mutation "${mutationKey}" doesn't exist`);
    return false;
    }

    self.status = 'mutation';

    let newState = self.mutations[mutationKey](self.state, payload);

    self.state = Object.assign(self.state, newState);

    return true;
}

案例(狀態(tài)管理的應(yīng)用)

需求說明:在首頁將一本書加入書架醇疼,書架列表自動(dòng)更新硕并。

store/state.js

export default {
    bookList: [],
};

store/mutation.js

export default {
  addBook(state, payload) {
    state.bookList.push(payload);
    return state;
  }
};

store/action.js

export default {
    addBook(context, payload) {
      context.commit('addBook', payload);
    },
};

store/index.js

import actions from './actions.js';
import mutations from './mutations.js';
import state from './state.js';
import Store from './store.js';

export default new Store({
    actions,
    mutations,
    state
});

訂閱(書架頁)

import store from '../store/index.js';

store.events.subscribe('stateChange', (params) => {
  this.setData({
    bookList: params.bookList
  });
});

發(fā)布(首頁)

import store from '../store/index.js';
store.dispatch('addBook',{bookid: 203});
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市秧荆,隨后出現(xiàn)的幾起案子鲤孵,更是在濱河造成了極大的恐慌,老刑警劉巖辰如,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件普监,死亡現(xiàn)場離奇詭異,居然都是意外死亡琉兜,警方通過查閱死者的電腦和手機(jī)凯正,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來豌蟋,“玉大人廊散,你說我怎么就攤上這事∥嗥#” “怎么了允睹?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長幌氮。 經(jīng)常有香客問我缭受,道長,這世上最難降的妖魔是什么该互? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任米者,我火速辦了婚禮,結(jié)果婚禮上宇智,老公的妹妹穿的比我還像新娘蔓搞。我一直安慰自己,他們只是感情好随橘,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布喂分。 她就那樣靜靜地躺著,像睡著了一般机蔗。 火紅的嫁衣襯著肌膚如雪蒲祈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天蜒车,我揣著相機(jī)與錄音讳嘱,去河邊找鬼。 笑死酿愧,一個(gè)胖子當(dāng)著我的面吹牛沥潭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嬉挡,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼钝鸽,長吁一口氣:“原來是場噩夢啊……” “哼汇恤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拔恰,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對情侶失蹤因谎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后颜懊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體财岔,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年河爹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了匠璧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咸这,死狀恐怖夷恍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情媳维,我是刑警寧澤酿雪,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站侄刽,受9級(jí)特大地震影響指黎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜唠梨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一袋励、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧当叭,春花似錦、人聲如沸盖灸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赁炎。三九已至醉箕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間徙垫,已是汗流浹背讥裤。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留姻报,地道東北人己英。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像吴旋,于是被迫代替她去往敵國和親损肛。 傳聞我的和親對象是個(gè)殘疾皇子厢破,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容