Vuex 2.0 學(xué)習(xí)筆記(一):框架原理

Vuex 是一個(gè)專為 Vue 服務(wù),用于管理頁面數(shù)據(jù)狀態(tài)易稠、提供統(tǒng)一數(shù)據(jù)操作的生態(tài)系統(tǒng)言秸。它專注于 MVC 模式中的 Model 層厅瞎,規(guī)定所有數(shù)據(jù)必需遵循action -> mutation -> state(change)的流程來進(jìn)行(在不需要異步操作并且交互邏輯比較簡單的時(shí)候,也可以直接通過commit觸發(fā)mutation來完成mutation -> state(change)的操作)硝烂,再結(jié)合 Vue 的數(shù)據(jù)視圖雙向綁定特性來實(shí)現(xiàn)頁面的展示更新箕别。統(tǒng)一的頁面狀態(tài)管理以及操作處理,可以讓復(fù)雜的組件交互變得簡單清晰滞谢,同時(shí)可在調(diào)試模式下進(jìn)行時(shí)光機(jī)般的倒退前進(jìn)操作串稀,查看數(shù)據(jù)改變過程,使 code debug 更加方便狮杨。

由于在前段時(shí)間的畢業(yè)設(shè)計(jì)中使用過 Vuex 來管理整個(gè)后臺系統(tǒng)的頁面狀態(tài)母截,也遇到了很多的坑,加上最近要進(jìn)行一個(gè)關(guān)于 Vuex 的技術(shù)分享橄教,就決定參考美團(tuán)點(diǎn)評技術(shù)團(tuán)隊(duì)的相關(guān)博客清寇,通過完整閱讀源碼來深入學(xué)習(xí)一下 Vuex 的實(shí)現(xiàn)原理。

Vuex 學(xué)習(xí)筆記將通過框架原理颤陶、源碼閱讀颗管、總結(jié)和應(yīng)用三個(gè)章節(jié)來分享這次的學(xué)習(xí)心得。

注:第一章主要是對框架原理的介紹滓走,并且通過一些代碼來簡單地描述在項(xiàng)目中應(yīng)該如何使用 Vuex 來對頁面進(jìn)行狀態(tài)管理垦江,真正遇到的項(xiàng)目可能會比這一章介紹的東西復(fù)雜得多。因此如果覺得我在這一章有什么沒有講清楚或者是有什么錯(cuò)誤,都?xì)g迎提出來比吭,也可以參考 Vuex 官方文檔進(jìn)行基礎(chǔ)概念的學(xué)習(xí)绽族。

1. 為什么要用Vuex ?

Vuex 的使用主要取決于我們的項(xiàng)目衩藤,官網(wǎng)的解釋是:

  • 當(dāng)我們構(gòu)建一個(gè)中大型的單頁面應(yīng)用程序時(shí)吧慢,Vuex 可以更好的幫助我們在組件外部統(tǒng)一管理狀態(tài)。

舉個(gè)例子赏表,當(dāng)我們在做一個(gè)基于 Vue 的商城項(xiàng)目時(shí)检诗,頂部都會有一個(gè) header 組件,它包含了我們登錄之后的用戶名瓢剿、購物車商品數(shù)量逢慌,而這個(gè)項(xiàng)目里面的任何一個(gè)頁面都會包含這個(gè) header 組件,因此這個(gè)組件是被很多組件引用的间狂。
為了方便我們在任何一個(gè)地方都能拿到這個(gè)組件里面的狀態(tài)攻泼,我們就可以把這些狀態(tài)放到 Vuex 里。而如果沒有 Vuex 的話鉴象,我們會發(fā)現(xiàn)在組件間傳參的時(shí)候需要不停地通過$emit進(jìn)行傳參忙菠,這種方式是十分麻煩的。組件比較少還好纺弊,一旦組件較多牛欢,需要一個(gè)狀態(tài)被很多組件所使用的話,我們進(jìn)行一次狀態(tài)改變淆游,就需要無數(shù)個(gè)$emit來完成全局狀態(tài)的改變氢惋,很痛苦也很難管理狀態(tài)。

Vuex 就可以把這些共用的狀態(tài)提出來稽犁,放到 Vuex 里面焰望,這樣所有組件都可以獲取到這個(gè)狀態(tài),可以想象成但并不等于window里面的全局變量已亥。

2. 框架運(yùn)行流程

對于 Vuex 框架熊赖,官方提供了一個(gè)相對完整的核心思想圖,這代表著整個(gè) Vuex 框架的運(yùn)行流程虑椎。

Vuex 核心思想圖

如圖所示震鹉,Vuex 為 Vue Components 建立起了一個(gè)完整的生態(tài)圈,包括在實(shí)際項(xiàng)目中對 API 的調(diào)用捆姜。圍繞這個(gè)生態(tài)圈传趾,簡要介紹一下各模塊在核心流程中的主要功能:

  • Vue Components:Vue 組件。HTML 頁面上泥技,負(fù)責(zé)接收用戶操作等交互行為浆兰,執(zhí)行 dispatch 方法觸發(fā)對應(yīng) action 進(jìn)行回應(yīng)。
  • dispatch:操作行為觸發(fā)方法,是唯一能執(zhí)行 action 的方法簸呈。
  • actions:操作行為處理模塊榕订。負(fù)責(zé)處理 Vue Components 接收到的所有交互行為。包含同步/異步操作蜕便,支持多個(gè)同名方法劫恒,按照注冊的順序依次觸發(fā)。向后臺 API 請求的操作就在這個(gè)模塊中進(jìn)行轿腺,包括觸發(fā)其他 action 以及提交 mutation 的操作两嘴。該模塊提供了 Promise 的封裝,以支持 action 的鏈?zhǔn)接|發(fā)族壳。
  • commit:狀態(tài)改變提交操作方法溶诞。對 mutation 進(jìn)行提交,是唯一能執(zhí)行 mutation 的方法决侈。
  • mutations:狀態(tài)改變操作方法。是 Vuex 修改 state 的唯一推薦方法喧务,其他修改方式在嚴(yán)格模式下將會報(bào)錯(cuò)赖歌。該方法只能進(jìn)行同步操作,且方法名只能全局唯一功茴。操作之中會有一些 hook 暴露出來庐冯,以進(jìn)行 state 的監(jiān)控等。
  • state:頁面狀態(tài)管理容器對象坎穿。集中存儲 Vue components 中 data 對象的零散數(shù)據(jù)展父,全局唯一,以進(jìn)行統(tǒng)一的狀態(tài)管理玲昧。頁面顯示所需的數(shù)據(jù)從該對象中進(jìn)行讀取栖茉,利用 Vue 的細(xì)粒度數(shù)據(jù)響應(yīng)機(jī)制來進(jìn)行高效的狀態(tài)更新。
  • getters:state 對象讀取方法孵延。圖中沒有單獨(dú)列出該模塊吕漂,應(yīng)該被包含在了 render 中,Vue Components 通過該方法讀取全局 state 對象尘应。

核心流程:Vue 組件接收交互行為惶凝,調(diào)用 dispatch 方法觸發(fā) action 相關(guān)處理,若頁面狀態(tài)需要改變犬钢,則調(diào)用 commit 方法提交 mutation 修改 state苍鲜,通過 getters 獲取到 state 新值,重新渲染 Vue Components玷犹,界面隨之更新混滔。

3. 核心模塊

在官方文檔中,提出了五個(gè)核心模塊:State、Getters遍坟、Mutations拳亿、Actions 和 Modules,而在一個(gè)使用 Vuex 的項(xiàng)目中愿伴,State 和 Mutations 是必需存在的肺魁。

3.1 State

什么是 State ?每一個(gè)組件的 data 中包含的變量都可以稱為 State隔节,它也是整個(gè) Vue 的核心概念鹅经。Vue 使用 State 來管理和操作 DOM,從而改變頁面的 UI怎诫,而不是像過去的那些方式(比如jQuery)一樣直接去操作 DOM瘾晃。關(guān)于 State 有兩個(gè)重要的概念:

  • State 是唯一的數(shù)據(jù)源。
  • 單一的狀態(tài)樹幻妓。
const Counter = {
    templete: `<div>{{ count }}</div>`,
    computed: {
        count() {
            return this.$store.count
        }
    }
}

這段代碼說明了蹦误,當(dāng)我們把變量count放到 Vuex 里面以后,所有的組件都可以通過這種方式獲取變量肉津,然后把它渲染到模板里面去强胰。如果你覺得這種方法比較 low(我也覺得),那么繼續(xù)往下看妹沙。

3.2 Getters

Getters 并不是必需品偶洋,但是在一些特定的場景還需要它出馬,在核心思想圖上并沒有標(biāo)出它存在的位置距糖,但是從它的使用方式來說玄窝,我覺得它被包含在了 State 和 Vue Components 之間的 Render 里面了。先看一下定義:

  • 通過 Getters 可以派生出一些新的狀態(tài)悍引。

怎么理解恩脂?先來看一段代碼:

const store = new Vuex.Store({
    state: {
        todos: [
            { id: 1, text: '...' , done: true },
            { id: 2, text: '...' , done: false }
        ]
    },
    getters: {
        doneTodos: state => {
            return state.todos.filter(todo => todo.done)
        }
    }
})

我們先實(shí)例化了一個(gè) Vuex,假設(shè)有很多組件都在使用 state 里的 todos 這個(gè)變量趣斤,而剛好有一個(gè)組件它只想獲取數(shù)組里done屬性的是true的對象东亦,就可以用 getters 來對返回值進(jìn)行處理』I可能有人會說典阵,那我把它拿到組件里再過濾不就行了嗎?好像是這么個(gè)道理镊逝,但是如果有五個(gè)組件需要獲取done屬性的是true的對象壮啊,那我們不就得寫五次的過濾方法了嗎?因此撑蒜,getters 也可以理解成是一個(gè)被提取出來的處理 state 對組件返回值的方法歹啼。

3.3 Mutations

提交 Mutations 是 Vuex 提供的唯一可以改變 State 的方法玄渗。看一下官方的話:

  • 更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation狸眼。
const store = new Vuex.Store({
    state: {
        count: 1
    },
    mutations: {
        increment(state) {
            state.count ++
        }
    }
})

我們通過上面的代碼可以簡單地定義一個(gè) mutation 藤树,但是還需要一個(gè)方法去觸發(fā)它,這就要用到commit方法:

store.commit('increment')

commit可以放在組件里面來提交 mutation拓萌,也可以在 action 里面提交 mutation岁钓。

注意:mutation 只能是同步的,不支持異步微王,當(dāng)我們需要使用異步的方法的時(shí)候屡限,就需要使用 action 異步地來觸發(fā) mutation。

3.4 Actions

Action 的作用上面已經(jīng)提到了炕倘,可以稍微總結(jié)一下:

  • Action 提交的是 mutation钧大,而不是直接變更狀態(tài)。
  • Action 可以包含異步操作罩旋。
const store = new Vuex.Store({
    state: {
        count: 1
    },
    mutations: {
        increment(state) {
            state.count ++
        }
    },
    actions: {
        increment(context) {
            context.commit('increment')
        }
    }
})

實(shí)際上啊央,Actions 的主要用處也就是封裝一些可以異步觸發(fā) mutation 的方法,組件可以使用dispatch方法調(diào)用action涨醋,包括和 API 的通信瓜饥。

3.5 Modules

最后,來了解一下 Modules东帅,其實(shí)很容易理解,我們在寫 js 代碼的時(shí)候球拦,經(jīng)常會根據(jù)模塊進(jìn)行拆分靠闭,Modules 也是這個(gè)思想。在編寫大型應(yīng)用的時(shí)候坎炼,需要 Vuex 管理的狀態(tài)比較多的時(shí)候愧膀,就需要把 Vuex 的 Store 對象分割成 module。

const moduleA = {
    state: { ... },
    mutations: { ... },
    actions: { ... },
    getters: { ... }
}

const moduleB = {
    state: { ... },
    mutations: { ... },
    actions: { ... },
    getters: { ... }
}

const store = new Vuex.Store({
    modules: {
        a: moduleA,
        b: moduleB
    }
})

一般情況下谣光,不是很復(fù)雜的項(xiàng)目我覺得并不需要拆分檩淋,也不一定要按照官方給的文件目錄來開發(fā)。只能說萄金,按方抓藥吧蟀悦。

4. 總結(jié)

關(guān)于 Vuex 的基本原理差不多就是這些了,但是由于它的特點(diǎn)氧敢,光看基本原理會發(fā)現(xiàn)什么都不會日戈,而且光看幾個(gè)小 demo 也讓人覺得它好像沒啥用,因此孙乖,學(xué)習(xí) Vuex 需要在具體的項(xiàng)目中運(yùn)用到浙炼,才能對它有一定的理解份氧。當(dāng)然,讀一讀源碼弯屈,知道它是怎么實(shí)現(xiàn)的也是很好的蜗帜。

Vuex.store 源碼實(shí)現(xiàn)邏輯

下一章:關(guān)于 Vuex 源碼的解析,就是根據(jù)這張來自美團(tuán)點(diǎn)評技術(shù)團(tuán)隊(duì)的 Vuex.store 源碼實(shí)現(xiàn)邏輯圖來進(jìn)行的资厉,有興趣的小伙伴可以先自己把源碼下下來根據(jù)流程看一看厅缺,文章大概周日更新。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酌住,一起剝皮案震驚了整個(gè)濱河市店归,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酪我,老刑警劉巖消痛,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異都哭,居然都是意外死亡秩伞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進(jìn)店門欺矫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纱新,“玉大人,你說我怎么就攤上這事穆趴×嘲” “怎么了?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵未妹,是天一觀的道長簿废。 經(jīng)常有香客問我,道長络它,這世上最難降的妖魔是什么族檬? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮化戳,結(jié)果婚禮上单料,老公的妹妹穿的比我還像新娘。我一直安慰自己点楼,他們只是感情好扫尖,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著掠廓,像睡著了一般藏斩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上却盘,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天狰域,我揣著相機(jī)與錄音媳拴,去河邊找鬼。 笑死兆览,一個(gè)胖子當(dāng)著我的面吹牛屈溉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抬探,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼子巾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了小压?” 一聲冷哼從身側(cè)響起线梗,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怠益,沒想到半個(gè)月后仪搔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜻牢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年烤咧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抢呆。...
    茶點(diǎn)故事閱讀 38,747評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡煮嫌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抱虐,到底是詐尸還是另有隱情昌阿,我是刑警寧澤,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布恳邀,位于F島的核電站懦冰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏轩娶。R本人自食惡果不足惜儿奶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一框往、第九天 我趴在偏房一處隱蔽的房頂上張望鳄抒。 院中可真熱鬧,春花似錦椰弊、人聲如沸许溅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贤重。三九已至,卻和暖如春清焕,著一層夾襖步出監(jiān)牢的瞬間并蝗,已是汗流浹背祭犯。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留滚停,地道東北人沃粗。 一個(gè)月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像键畴,于是被迫代替她去往敵國和親最盅。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評論 2 350

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