8.Vuex 狀態(tài)管理的工作原理

Vuex 狀態(tài)管理的工作原理

為什么要使用 Vuex

當(dāng)我們使用 Vue.js 來(lái)開(kāi)發(fā)一個(gè)單頁(yè)應(yīng)用時(shí),經(jīng)常會(huì)遇到一些組件間共享的數(shù)據(jù)或狀態(tài)敏簿,或是需要通過(guò) props 深層傳遞的一些數(shù)據(jù)扇调。在應(yīng)用規(guī)模較小的時(shí)候擂送,我們會(huì)使用 props弄贿、事件等常用的父子組件的組件間通信方法液斜,或者是通過(guò)事件總線來(lái)進(jìn)行任意兩個(gè)組件的通信求类。但是當(dāng)應(yīng)用逐漸復(fù)雜后奔垦,問(wèn)題就開(kāi)始出現(xiàn)了,這樣的通信方式會(huì)導(dǎo)致數(shù)據(jù)流異常地混亂。

這個(gè)時(shí)候,我們就需要用到我們的狀態(tài)管理工具 Vuex 了啼染。Vuex 是一個(gè)專門為 Vue.js 框架設(shè)計(jì)的够傍、專門用來(lái)對(duì)于 Vue.js 應(yīng)用進(jìn)行狀態(tài)管理的庫(kù)。它借鑒了 Flux悦析、redux 的基本思想,將狀態(tài)抽離到全局,形成一個(gè) Store筐咧。因?yàn)?Vuex 內(nèi)部采用了 new Vue 來(lái)將 Store 內(nèi)的數(shù)據(jù)進(jìn)行「響應(yīng)式化」,所以 Vuex 是一款利用 Vue 內(nèi)部機(jī)制的庫(kù)噪矛,與 Vue 高度契合量蕊,與 Vue 搭配使用顯得更加簡(jiǎn)單高效,但缺點(diǎn)是不能與其他的框架(如 react)配合使用摩疑。

本節(jié)將簡(jiǎn)單介紹 Vuex 最核心的內(nèi)部機(jī)制危融,起個(gè)拋磚引玉的作用,想了解更多細(xì)節(jié)可以參考筆者 Github 上的另一篇文章 《Vuex源碼解析》或者直接閱讀 Vuex源碼雷袋。

安裝

Vue.js 提供了一個(gè) Vue.use 的方法來(lái)安裝插件吉殃,內(nèi)部會(huì)調(diào)用插件提供的 install 方法辞居。

Vue.use(Vuex);

所以我們的插件需要提供一個(gè) install 方法來(lái)安裝。

let Vue;

export default install (_Vue) {
    Vue.mixin({ beforeCreate: vuexInit });
    Vue = _Vue;
}

我們采用 Vue.mixin 方法將 vuexInit 方法混淆進(jìn) beforeCreate 鉤子中蛋勺,并用 Vue 保存 Vue 對(duì)象瓦灶。那么 vuexInit 究竟實(shí)現(xiàn)了什么呢?

我們知道抱完,在使用 Vuex 的時(shí)候贼陶,我們需要將 store 傳入到 Vue 實(shí)例中去。

/*將store放入Vue創(chuàng)建時(shí)的option中*/
new Vue({
    el: '#app',
    store
});

但是我們卻在每一個(gè) vm 中都可以訪問(wèn)該 store巧娱,這個(gè)就需要靠 vuexInit 了碉怔。

function vuexInit () {
    const options = this.$options;
    if (options.store) {
        this.$store = options.store;
    } else {
        this.$store = options.parent.$store;
    }
}

因?yàn)橹耙呀?jīng)用Vue.mixin 方法將 vuexInit 方法混淆進(jìn) beforeCreate 鉤子中,所以每一個(gè) vm 實(shí)例都會(huì)調(diào)用 vuexInit 方法禁添。

如果是根節(jié)點(diǎn)($options中存在 store 說(shuō)明是根節(jié)點(diǎn))撮胧,則直接將 options.store 賦值給 this.$store。否則則說(shuō)明不是根節(jié)點(diǎn)老翘,從父節(jié)點(diǎn)的 $store 中獲取芹啥。

通過(guò)這步的操作,我們已經(jīng)可以在任意一個(gè) vm 中通過(guò) this.$store 來(lái)訪問(wèn) Store 的實(shí)例啦~

Store

數(shù)據(jù)的響應(yīng)式化

首先我們需要在 Store 的構(gòu)造函數(shù)中對(duì) state 進(jìn)行「響應(yīng)式化」铺峭。

constructor () {
    this._vm = new Vue({
        data: {
            $$state: this.state
        }
    })
}

熟悉「響應(yīng)式」的同學(xué)肯定知道墓怀,這個(gè)步驟以后,state 會(huì)將需要的依賴收集在 Dep 中卫键,在被修改時(shí)更新對(duì)應(yīng)視圖傀履。我們來(lái)看一個(gè)小例子。

let globalData = {
    d: 'hello world'
};
new Vue({
    data () {
        return {
            $$state: {
                globalData
            }
        }
    }
});

/* modify */
setTimeout(() => {
    globalData.d = 'hi~';
}, 1000);

Vue.prototype.globalData = globalData;

任意模板中

<div>{{globalData.d}}</div>

上述代碼在全局有一個(gè) globalData永罚,它被傳入一個(gè) Vue 對(duì)象的 data 中啤呼,之后在任意 Vue 模板中對(duì)該變量進(jìn)行展示,因?yàn)榇藭r(shí) globalData 已經(jīng)在 Vue 的 prototype 上了所以直接通過(guò) this.prototype 訪問(wèn)呢袱,也就是在模板中的 {{globalData.d}}官扣。此時(shí),setTimeout 在 1s 之后將 globalData.d 進(jìn)行修改羞福,我們發(fā)現(xiàn)模板中的 globalData.d 發(fā)生了變化惕蹄。其實(shí)上述部分就是 Vuex 依賴 Vue 核心實(shí)現(xiàn)數(shù)據(jù)的“響應(yīng)式化”。

講完了 Vuex 最核心的通過(guò) Vue 進(jìn)行數(shù)據(jù)的「響應(yīng)式化」治专,接下來(lái)我們?cè)賮?lái)介紹兩個(gè) Store 的 API卖陵。

commit

首先是 commit 方法,我們知道 commit 方法是用來(lái)觸發(fā) mutation 的张峰。

commit (type, payload, _options) {
    const entry = this._mutations[type];
    entry.forEach(function commitIterator (handler) {
        handler(payload);
    });
}

_mutations 中取出對(duì)應(yīng)的 mutation泪蔫,循環(huán)執(zhí)行其中的每一個(gè) mutation。

dispatch

dispatch 同樣道理喘批,用于觸發(fā) action撩荣,可以包含異步狀態(tài)铣揉。

dispatch (type, payload) {
    const entry = this._actions[type];

    return entry.length > 1
    ? Promise.all(entry.map(handler => handler(payload)))
    : entry[0](payload);
}

同樣的,取出 _actions 中的所有對(duì)應(yīng) action餐曹,將其執(zhí)行逛拱,如果有多個(gè)則用 Promise.all 進(jìn)行包裝。

最后

理解 Vuex 的核心在于理解其如何與 Vue 本身結(jié)合台猴,如何利用 Vue 的響應(yīng)式機(jī)制來(lái)實(shí)現(xiàn)核心 Store 的「響應(yīng)式化」朽合。

Vuex 本身代碼不多且設(shè)計(jì)優(yōu)雅,非常值得一讀饱狂,想閱讀源碼的同學(xué)請(qǐng)看Vuex源碼曹步。

注:本節(jié)代碼參考《Vuex狀態(tài)管理的工作原理》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末休讳,一起剝皮案震驚了整個(gè)濱河市箭窜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌衍腥,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纳猫,死亡現(xiàn)場(chǎng)離奇詭異婆咸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)芜辕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門尚骄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人侵续,你說(shuō)我怎么就攤上這事倔丈。” “怎么了状蜗?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵需五,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我轧坎,道長(zhǎng)宏邮,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任缸血,我火速辦了婚禮蜜氨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捎泻。我一直安慰自己飒炎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布笆豁。 她就那樣靜靜地躺著郎汪,像睡著了一般赤赊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上怒竿,一...
    開(kāi)封第一講書(shū)人閱讀 51,198評(píng)論 1 299
  • 那天砍鸠,我揣著相機(jī)與錄音,去河邊找鬼耕驰。 笑死爷辱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的朦肘。 我是一名探鬼主播饭弓,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼媒抠!你這毒婦竟也來(lái)了弟断?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤趴生,失蹤者是張志新(化名)和其女友劉穎阀趴,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體苍匆,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡刘急,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浸踩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叔汁。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖检碗,靈堂內(nèi)的尸體忽然破棺而出据块,到底是詐尸還是另有隱情,我是刑警寧澤折剃,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布另假,位于F島的核電站,受9級(jí)特大地震影響怕犁,放射性物質(zhì)發(fā)生泄漏浪谴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一因苹、第九天 我趴在偏房一處隱蔽的房頂上張望苟耻。 院中可真熱鬧,春花似錦扶檐、人聲如沸凶杖。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)智蝠。三九已至腾么,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間杈湾,已是汗流浹背解虱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留漆撞,地道東北人殴泰。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像浮驳,于是被迫代替她去往敵國(guó)和親悍汛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

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

  • 寫(xiě)在前面 因?yàn)閷?duì)Vue.js很感興趣至会,而且平時(shí)工作的技術(shù)棧也是Vue.js离咐,這幾個(gè)月花了些時(shí)間研究學(xué)習(xí)了一下Vue...
    染陌同學(xué)閱讀 1,670評(píng)論 0 12
  • Vuex是什么? Vuex 是一個(gè)專為 Vue.js應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式奉件。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件...
    蕭玄辭閱讀 3,114評(píng)論 0 6
  • Vuex 是什么宵蛀? Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有...
    skycolor閱讀 833評(píng)論 0 1
  • Vuex Vuex是一個(gè)專門為Vue.js應(yīng)用所設(shè)計(jì)的集中式狀態(tài)管理架構(gòu)县貌,它借鑒了Flux和Redux的設(shè)計(jì)思想糖埋,...
    JunChow520閱讀 1,570評(píng)論 2 0
  • 本來(lái)寫(xiě)了電影《但丁密碼》的觀后感,寫(xiě)完之后,準(zhǔn)備上傳一張圖片亮化一個(gè)版面,可是不知道碰到了哪里,閃退,全沒(méi)了,怎么...
    雨漫漫閱讀 257評(píng)論 0 0