Vuex(狀態(tài)管理模式)

Vuex 是什么镰官?

Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式拓哺。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài)哨苛,并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。Vuex 也集成到 Vue 的官方調(diào)試工具 devtools extension茅坛,提供了諸如零配置的 time-travel 調(diào)試、狀態(tài)快照導(dǎo)入導(dǎo)出等高級調(diào)試功能眠屎。

使用

在 Vue 的單頁面應(yīng)用中使用阿宅,需要使用Vue.use(Vuex)調(diào)用插件,將其注入到Vue根實(shí)例中绒窑。

import Vuex from 'vuex'

Vue.use(Vuex)
// 各組件相互共享數(shù)據(jù)的插件

export default new Vuex.Store({
  // 數(shù)據(jù)存放地方
  state: {
},
  // 方法存放地方
  mutations: {
},
  // 反復(fù)存放地方(可以執(zhí)行ajax)
  actions: {
  },
  // 模塊
  modules: {
  }
})

核心

  • State葬燎,Getter郊丛,Mutation,Action,Module困檩,

Vuex 主要有四部分:

  • state:包含了store中存儲的各個狀態(tài)逢唤。
  • getter: 類似于 Vue 中的計(jì)算屬性蜻展,根據(jù)其他 getter 或 state 計(jì)算返回值。
  • mutation: 一組方法蠕搜,是改變store中狀態(tài)的執(zhí)行者,只能是同步操作岳颇。
  • action: 一組方法,其中可以包含異步操作原献。

State

Vuex 使用 state 來存儲應(yīng)用中需要共享的狀態(tài)叮盘。為了能讓 Vue 組件在 state更改后也隨著更改培漏,需要基于state 創(chuàng)建計(jì)算屬性。

// 創(chuàng)建一個 Counter 組件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count  // count 為某個狀態(tài)
    }
  }
}

Getter

類似于 Vue 中的 計(jì)算屬性(可以認(rèn)為是 store 的計(jì)算屬性),getter 的返回值會根據(jù)它的依賴被緩存起來习瑰,且只有當(dāng)它的依賴值發(fā)生了改變才會被重新計(jì)算。

Getter 方法接受 state 作為其第一個參數(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)
    }
  }
})

通過屬性訪問

Getter 會暴露為 store.getters 對象,可以以屬性的形式訪問這些值:

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]

Getter 方法也接受 state和其他getters作為前兩個參數(shù)润讥。

getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}
store.getters.doneTodosCount // -> 1

我們可以很容易地在任何組件中使用它:

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

注意: getter 在通過屬性訪問時是作為 Vue 的響應(yīng)式系統(tǒng)的一部分緩存其中的常潮。

通過方法訪問

也可以通過讓 getter 返回一個函數(shù)献联,來實(shí)現(xiàn)給 getter 傳參胁镐。在對 store 里的數(shù)組進(jìn)行查詢時非常有用。

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

注意: getter 在通過方法訪問時阿弃,每次都會去進(jìn)行調(diào)用,而不會緩存結(jié)果伴箩。

Mutation

更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation。也就是說竟闪,前面兩個都是狀態(tài)值本身暗挑,mutations才是改變狀態(tài)的執(zhí)行者也殖。

注意:mutations只能是同步地更改狀態(tài)土思。

Vuex 中的 mutation 非常類似于事件:每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調(diào)函數(shù) (handler)务热。這個回調(diào)函數(shù)就是我們實(shí)際進(jìn)行狀態(tài)更改的地方,并且它會接受 state 作為第一個參數(shù):

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 變更狀態(tài)
      state.count++
    }
  }
})

調(diào)用 store.commit 方法:

store.commit('increment')

提交載荷(Payload)

// ...
mutations: {
  increment (state, n) {
    state.count += n
  }
}
this.$store.commit('increment', 10)

其中己儒,第一個參數(shù)是state崎岂,后面的參數(shù)是向 store.commit 傳入的額外的參數(shù),即 mutation 的 載荷(payload)闪湾。

store.commit方法的第一個參數(shù)是要發(fā)起的mutation類型名稱冲甘,后面的參數(shù)均當(dāng)做額外數(shù)據(jù)傳入mutation定義的方法中。

規(guī)范的發(fā)起mutation的方式如下:

// 以載荷形式
store.commit('increment'途样,{
  amount: 10   //這是額外的參數(shù)
})

// 或者使用對象風(fēng)格的提交方式
store.commit({
  type: 'increment',
  amount: 10   //這是額外的參數(shù)
})

額外的參數(shù)會封裝進(jìn)一個對象江醇,作為第二個參數(shù)傳入mutation定義的方法中。

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}

Action

想要異步地更改狀態(tài)何暇,就需要使用 action陶夜。action并不直接改變state,而是發(fā)起mutation裆站。

注冊一個簡單的 action:

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

Action 函數(shù)接受一個與 store 實(shí)例具有相同方法和屬性的 context 對象律适,因此你可以調(diào)用 context.commit 提交一個 mutation,或者通過 context.state 和 context.getters 來獲取 state 和 getters遏插。

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}

在action內(nèi)部執(zhí)行異步操作:

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

發(fā)起action的方法形式和發(fā)起mutation一樣捂贿,只是換了個名字dispatch。

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

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

Action處理異步的正確使用方式

想要使用action處理異步工作很簡單胳嘲,只需要將異步操作放到action中執(zhí)行要想在異步操作完成后繼續(xù)進(jìn)行相應(yīng)的流程操作厂僧,有兩種方式:

  1. store.dispatch返回相應(yīng)action的執(zhí)行結(jié)果,而action的處理函數(shù)返回的就是Promise了牛,所以store.dispatch仍然返回一個Promise颜屠。

    actions: {
      actionA ({ commit }) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            commit('someMutation')
            resolve()
          }, 1000)
        })
      }
    }
    

    現(xiàn)在可以寫成:

    store.dispatch('actionA').then(() => {
      // ...
    })
    

    在另外一個 action 中也可以:

    actions: {
      // ...
      actionB ({ dispatch, commit }) {
        return dispatch('actionA').then(() => {
          commit('someOtherMutation')
        })
      }
    }
    
  2. 利用async/await 進(jìn)行組合action。代碼更加簡潔鹰祸。

    // 假設(shè) getData() 和 getOtherData() 返回的是 Promise
    
    actions: {
      async actionA ({ commit }) {
        commit('gotData', await getData())
      },
      async actionB ({ dispatch, commit }) {
        await dispatch('actionA') // 等待 actionA 完成
        commit('gotOtherData', await getOtherData())
      }
    }
    

    一個 store.dispatch在不同模塊中可以觸發(fā)多個 action 函數(shù)甫窟。在這種情況下,只有當(dāng)所有觸發(fā)函數(shù)完成后蛙婴,返回的 Promise 才會執(zhí)行粗井。

Action與Mutation的區(qū)別

Action 類似于 mutation,不同在于:

  • Action 提交的是 mutation街图,而不是直接變更狀態(tài)浇衬。
  • Action 可以包含任意異步操作,而Mutation只能且必須是同步操作餐济。

Module

  • 由于使用單一狀態(tài)樹耘擂,應(yīng)用的所有狀態(tài)會集中到一個比較大的對象。當(dāng)應(yīng)用變得非常復(fù)雜時絮姆,store 對象就有可能變得相當(dāng)臃腫醉冤。

  • 這時我們可以將 store 分割為模塊(module)秩霍,每個模塊擁有自己的 stategetters 蚁阳、mutations 前域、actions 、甚至是嵌套子模塊——從上至下進(jìn)行同樣方式的分割韵吨。

代碼示例:

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

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

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

store.state.a // -> moduleA 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匿垄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子归粉,更是在濱河造成了極大的恐慌椿疗,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糠悼,死亡現(xiàn)場離奇詭異届榄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)倔喂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門铝条,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人席噩,你說我怎么就攤上這事班缰。” “怎么了悼枢?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵埠忘,是天一觀的道長。 經(jīng)常有香客問我馒索,道長莹妒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任绰上,我火速辦了婚禮旨怠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蜈块。我一直安慰自己鉴腻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布疯趟。 她就那樣靜靜地躺著拘哨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪信峻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天瓮床,我揣著相機(jī)與錄音盹舞,去河邊找鬼产镐。 笑死,一個胖子當(dāng)著我的面吹牛踢步,可吹牛的內(nèi)容都是我干的癣亚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼获印,長吁一口氣:“原來是場噩夢啊……” “哼述雾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起兼丰,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤玻孟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鳍征,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體黍翎,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年艳丛,在試婚紗的時候發(fā)現(xiàn)自己被綠了匣掸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡氮双,死狀恐怖碰酝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情戴差,我是刑警寧澤砰粹,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站造挽,受9級特大地震影響碱璃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜饭入,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一嵌器、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谐丢,春花似錦爽航、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至窄瘟,卻和暖如春衷佃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蹄葱。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工氏义, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锄列,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓惯悠,卻偏偏與公主長得像邻邮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子克婶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

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

  • Vuex 是什么筒严? Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應(yīng)用的所有...
    skycolor閱讀 833評論 0 1
  • state: 最底層的初始數(shù)據(jù) getters: 相當(dāng)于vue的計(jì)算屬性情萤,對state數(shù)據(jù)進(jìn)行處理 鸭蛙、擴(kuò)展 mu...
    唯軒_443e閱讀 910評論 0 0
  • 對于學(xué)習(xí)過react的同學(xué)可能比較清楚,在react我們是通過redux來處理狀態(tài)管理的紫岩,那么現(xiàn)在火熱的vue是如...
    我是上帝可愛多閱讀 2,862評論 0 4
  • 習(xí)慣養(yǎng)成很容易规惰,戒掉卻很難!H颉歇万! 什么是Vuex? Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式...
    前端又又閱讀 2,769評論 0 1
  • 材料:鐵絲 粗 細(xì) 拉菲草 粗鐵絲纏上拉菲草 中間對折,根部纏繞 平均分開诅愚, 中間纏繞 如圖 外...
    花藝先生閱讀 975評論 1 3