Vue的Flux框架--Vuex

image

本文內(nèi)容主要參考官方教程,為了方便理解垃杖,用更加通俗的文字講解Vuex男杈,也原文內(nèi)容做一些重點(diǎn)引用。希望會(huì)對(duì)你有所幫助调俘。

學(xué)習(xí)vue之前伶棒,最重要是弄懂兩個(gè)概念,一是“what”彩库,要理解vuex是什么肤无;二是“why”,要清楚為什么要用vuex

Vuex是什么骇钦?

Vuex 類(lèi)似 React 里面的 Redux 的狀態(tài)管理器宛渐,用來(lái)管理Vue的所有組件狀態(tài)。

為什么使用Vuex司忱?

當(dāng)你打算開(kāi)發(fā)大型單頁(yè)應(yīng)用(SPA)皇忿,會(huì)出現(xiàn)多個(gè)視圖組件依賴(lài)同一個(gè)狀態(tài)畴蹭,來(lái)自不同視圖的行為需要變更同一個(gè)狀態(tài)坦仍。

遇到以上情況時(shí)候,你就應(yīng)該考慮使用Vuex了叨襟,它能把組件的共享狀態(tài)抽取出來(lái)繁扎,當(dāng)做一個(gè)全局單例模式進(jìn)行管理。這樣不管你在何處改變狀態(tài)糊闽,都會(huì)通知使用該狀態(tài)的組件做出相應(yīng)修改梳玫。

下面講解如何使用Vuex

一個(gè)簡(jiǎn)單的Vuex示例

本文就講解安裝Vuex,直接通過(guò)代碼講解Vuex使用右犹。

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {
        increment (state) {
            state.count++
        }
    }
})

上面就是一個(gè)簡(jiǎn)單的Vuex示例提澎,每一個(gè)Vuex應(yīng)用就是一個(gè)store,在store中包含組件中的共享狀態(tài)state和改變狀態(tài)的方法(暫且稱(chēng)作方法)mutations念链。

需要注意的是只能通過(guò)mutations改變store的state的狀態(tài)盼忌,不能通過(guò)store.state.count = 5;直接更改(其實(shí)可以更改积糯,不建議這么做,不通過(guò)mutations改變state谦纱,狀態(tài)不會(huì)被同步)看成。

使用store.commit方法觸發(fā)mutations改變state:

store.commit('increment');

console.log(store.state.count)  // 1

一個(gè)簡(jiǎn)簡(jiǎn)單單的Vuex應(yīng)用就實(shí)現(xiàn)了。

在Vue組件使用Vuex

如果希望Vuex狀態(tài)更新的時(shí)候跨嘉,組件數(shù)據(jù)得到相應(yīng)的更新川慌,那么可以用計(jì)算屬性computed獲取state的更新?tīng)顟B(tài)。

const Counter = {
    template: `<div>{{ count }}</div>`,
    computed: {
        count () {
            return store.state.count;
        }
    }
}

每一個(gè)store.state都是全局狀態(tài)祠乃,在使用Vuex時(shí)候需要在根組件或(入口文件)注入梦重。

// 根組件
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);
const app = new Vue({
    el: '#app',
    store,
    components: {
        Counter
    },
    template: `
        <div class="app">
            <counter></counter>
        </div>
    `
})

通過(guò)這種注入機(jī)制,就能在子組件Counter通過(guò)this.$store訪問(wèn):

// Counter 組件
const Counter = {
    template: `<div>{{ count }}</div>`,
    computed: {
        count () {
            return this.$store.state.count
        }
    }
}

mapState函數(shù)

computed: {
    count () {
        return this.$store.state.count
    }
}

上面通過(guò)count計(jì)算屬性獲取同名state.count屬性跳纳,如何每一次獲取都要寫(xiě)一個(gè)這樣的方法忍饰,是不顯得重復(fù)又麻煩?可以使用mapState函數(shù)簡(jiǎn)化這個(gè)過(guò)程寺庄。

import { mapState } from 'vuex';

export default {
    computed: mapState ({
        count: state => state.count,
        countAlias: 'count',    // 別名 `count` 等價(jià)于 state => state.count
    })
}

還有更簡(jiǎn)單的使用方法:

computed: mapState([
  'count' 
  // 映射 this.count 為 store.state.count
])

Getters對(duì)象

如果我們需要對(duì)state對(duì)象進(jìn)行做處理計(jì)算艾蓝,如下:

computed: {
    doneTodosCount () {
        return this.$store.state.todos.filter(todo => todo.done).length
    }
}

如果多個(gè)組件都要進(jìn)行這樣的處理,那么就要在多個(gè)組件中復(fù)制該函數(shù)斗塘。這樣是很沒(méi)有效率的事情赢织,當(dāng)這個(gè)處理過(guò)程更改了,還有在多個(gè)組件中進(jìn)行同樣的更改馍盟,這就更加不易于維護(hù)于置。

Vuex中g(shù)etters對(duì)象,可以方便我們?cè)趕tore中做集中的處理贞岭。Getters接受state作為第一個(gè)參數(shù):

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)
    }
  }
})

在Vue中通過(guò)store.getters對(duì)象調(diào)用:

computed: {
  doneTodos () {
    return this.$store.getters.doneTodos
  }
}

Getter也可以接受其他getters作為第二個(gè)參數(shù):

getters: {
  doneTodos: state => {
      return state.todos.filter(todo => todo.done)
  },
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}

mapGetters輔助函數(shù)

與mapState類(lèi)似八毯,都能達(dá)到簡(jiǎn)化代碼的效果。mapGetters輔助函數(shù)僅僅是將store中的getters映射到局部計(jì)算屬性:

import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
    // 使用對(duì)象展開(kāi)運(yùn)算符將 getters 混入 computed 對(duì)象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}

上面也可以寫(xiě)作:

computed: mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])

所以在Vue的computed計(jì)算屬性中會(huì)存在兩種輔助函數(shù):

import { mapState, mapGetters } from 'vuex';

export default {
    // ...
    computed: {
        ...mapGetters([ ... ]),
        ...mapState([ ... ])
    }
}

Mutations

之前也說(shuō)過(guò)了瞄桨,更改Vuex的store中的狀態(tài)的唯一方法就是mutations话速。

每一個(gè)mutation都有一個(gè)事件類(lèi)型type和一個(gè)回調(diào)函數(shù)handler。

調(diào)用mutation芯侥,需要通過(guò)store.commit方法調(diào)用mutation type:

store.commit('increment')

Payload 提交載荷

也可以向store.commit傳入第二參數(shù)泊交,也就是mutation的payload:

mutaion: {
    increment (state, n) {
        state.count += n;
    }
}

store.commit('increment', 10);

單單傳入一個(gè)n,可能并不能滿(mǎn)足我們的業(yè)務(wù)需要柱查,這時(shí)候我們可以選擇傳入一個(gè)payload對(duì)象:

mutation: {
    increment (state, payload) {
        state.totalPrice += payload.price + payload.count;
    }
}

store.commit({
    type: 'increment',
    price: 10,
    count: 8
})

mapMutations函數(shù)

不例外廓俭,mutations也有映射函數(shù)mapMutations,幫助我們簡(jiǎn)化代碼唉工,使用mapMutations輔助函數(shù)將組件中的methods映射為store.commit調(diào)用研乒。

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment' // 映射 this.increment() 為 this.$store.commit('increment')
    ]),
    ...mapMutations({
      add: 'increment' // 映射 this.add() 為 this.$store.commit('increment')
    })
  }
}

注 Mutations必須是同步函數(shù)。
如果我們需要異步操作和提交多個(gè)Mutations淋硝,Mutations就不能滿(mǎn)足我們需求了雹熬,這時(shí)候我們就需要Actions了错维。

Actions

Action 類(lèi)似于 mutation,不同在于:

  • Action 提交的是 mutation橄唬,而不是直接變更狀態(tài)赋焕。
  • Action 可以包含任意異步操作。

讓我們來(lái)注冊(cè)一個(gè)簡(jiǎn)單的 action:

var store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment: function(state) {
      state.count++;
    }
  },
  actions: {
    increment: function(store) {
      store.commit('increment');
    }
  }
});

Action 函數(shù)接受一個(gè)與 store 實(shí)例具有相同方法和屬性的 context 對(duì)象仰楚,因此你可以調(diào)用 context.commit 提交一個(gè) mutation隆判,或者通過(guò) context.state 和 context.getters 來(lái)獲取 state 和 getters。

分發(fā) Action

Action 通過(guò) store.dispatch 方法觸發(fā):

乍一眼看上去感覺(jué)多此一舉僧界,我們直接分發(fā) mutation 豈不更方便侨嘀?實(shí)際上并非如此,還記得 mutation必須同步執(zhí)行這個(gè)限制么捂襟?Action就不受約束! 我們可以在 action 內(nèi)部執(zhí)行異步操作:

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

Actions 支持同樣的載荷方式和對(duì)象方式進(jìn)行分發(fā):

// 以載荷形式分發(fā)
store.dispatch('incrementAsync', {
  amount: 10
})

// 以對(duì)象形式分發(fā)
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

同樣地咬腕,action也有相對(duì)應(yīng)的mapActions 輔助函數(shù)

mapActions

mapActions 輔助函數(shù)跟mapMutations一樣都是組件的 methods 調(diào)用:

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment' // 映射 this.increment() 為 this.$store.dispatch('increment')
    ]),
    ...mapActions({
      add: 'increment' // 映射 this.add() 為 this.$store.dispatch('increment')
    })
  }
}

mutation-types

關(guān)于mutation-types方面的講解官方文檔很少說(shuō)明,但在實(shí)際的中大項(xiàng)目中葬荷,對(duì)==mutation-types==的配置是必不可少的涨共,Vuex的文檔只講解了state,getters,mutation,actions四個(gè)核心概念,下面我簡(jiǎn)單補(bǔ)充下mutation-types的使用宠漩。

顧名思義举反,==mutation-types==其實(shí)就是mutation實(shí)例中各個(gè)方法的設(shè)定,一般要mutation方法前先在mutation-types用大寫(xiě)寫(xiě)法設(shè)定扒吁,再在mutation里引入使用火鼻,下面看看項(xiàng)目實(shí)際使用:

項(xiàng)目組織結(jié)構(gòu)

image

在mutation-types定義好mutation的方法結(jié)構(gòu):

//SET_SINGER,SET_SONG 為mutation中要使用的方法名

export const SET_SINGER = 'SET_SINGER'

export const SET_SONG = 'SET_SONG'

在mutation中導(dǎo)入使用:

import * as types from ',/mutation-types.js'

const mutations = {
    [types.SET_SINGER](state, singer) {
       .... 
    },
    [types.SET_SONG](state, song) {
       .... 
    }
}

結(jié)語(yǔ)

看完上面對(duì)vuex的講解相信你已經(jīng)入門(mén)了,現(xiàn)在可以看看具體的項(xiàng)目加深理解雕崩,可以參考我的github一個(gè)購(gòu)物車(chē)?yán)? https://github.com/osjj/vue-shopCart

image

image

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末魁索,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子盼铁,更是在濱河造成了極大的恐慌粗蔚,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捉貌,死亡現(xiàn)場(chǎng)離奇詭異支鸡,居然都是意外死亡冬念,警方通過(guò)查閱死者的電腦和手機(jī)趁窃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)急前,“玉大人醒陆,你說(shuō)我怎么就攤上這事●烧耄” “怎么了刨摩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵寺晌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我澡刹,道長(zhǎng)呻征,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任罢浇,我火速辦了婚禮陆赋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嚷闭。我一直安慰自己攒岛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布胞锰。 她就那樣靜靜地躺著灾锯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嗅榕。 梳的紋絲不亂的頭發(fā)上顺饮,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天,我揣著相機(jī)與錄音凌那,去河邊找鬼领突。 笑死,一個(gè)胖子當(dāng)著我的面吹牛案怯,可吹牛的內(nèi)容都是我干的君旦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼嘲碱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼金砍!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起麦锯,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤恕稠,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后扶欣,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鹅巍,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年料祠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了骆捧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡髓绽,死狀恐怖敛苇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情顺呕,我是刑警寧澤枫攀,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布括饶,位于F島的核電站,受9級(jí)特大地震影響来涨,放射性物質(zhì)發(fā)生泄漏图焰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一蹦掐、第九天 我趴在偏房一處隱蔽的房頂上張望楞泼。 院中可真熱鬧,春花似錦笤闯、人聲如沸堕阔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)超陆。三九已至,卻和暖如春浦马,著一層夾襖步出監(jiān)牢的瞬間时呀,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工晶默, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谨娜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓磺陡,卻偏偏與公主長(zhǎng)得像趴梢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子币他,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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

  • 安裝 npm npm install vuex --save 在一個(gè)模塊化的打包系統(tǒng)中坞靶,您必須顯式地通過(guò)Vue.u...
    蕭玄辭閱讀 2,945評(píng)論 0 7
  • Vuex是什么? Vuex 是一個(gè)專(zhuān)為 Vue.js應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式蝴悉。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件...
    蕭玄辭閱讀 3,122評(píng)論 0 6
  • vuex 場(chǎng)景重現(xiàn):一個(gè)用戶(hù)在注冊(cè)頁(yè)面注冊(cè)了手機(jī)號(hào)碼彰阴,跳轉(zhuǎn)到登錄頁(yè)面也想拿到這個(gè)手機(jī)號(hào)碼,你可以通過(guò)vue的組件化...
    sunny519111閱讀 8,022評(píng)論 4 111
  • Vuex 是一個(gè)專(zhuān)為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式拍冠。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài)尿这,并以相應(yīng)...
    白水螺絲閱讀 4,670評(píng)論 7 61
  • 上一章總結(jié)了 Vuex 的框架原理,這一章我們將從 Vuex 的入口文件開(kāi)始庆杜,分步驟閱讀和解析源碼射众。由于 Vuex...
    你的肖同學(xué)閱讀 1,790評(píng)論 3 16