vuex 狀態(tài)管理


對(duì)于小型應(yīng)用來說饥漫,完全沒用必要引入狀態(tài)管理叽掘,因?yàn)檫@會(huì)帶來更多的開發(fā)成本。
對(duì)于組件化開發(fā)來講邻储,大型應(yīng)用的狀態(tài)往往跨越多個(gè)組件丙笋。在多層嵌套的父子組件之間傳遞狀態(tài)已經(jīng)十分麻煩答渔,而Vue更是沒用為兄弟組件提供直接共享數(shù)據(jù)的方法卦溢。
基于這個(gè)問題佳鳖,許多框架提供了解決方案——使用全局的狀態(tài)管理器,將所有分散的共享數(shù)據(jù)交由狀態(tài)管理器保管棚赔。

  • vuex適用于大型項(xiàng)目中,在小型項(xiàng)目中使用sessionStoragelocalStorage徘郭。

一靠益、什么是vuex?

1.1 vuex的定義

vuex就是用來集中管理組件狀態(tài)残揉,稱為組件狀態(tài)管理模式胧后,適合組件中存在大量密集的數(shù)據(jù)傳遞的情況。

  • 每一個(gè)Vuex應(yīng)用的核心都是一個(gè)store(倉庫)抱环,你也可以理解它是一個(gè)“非凡的全局對(duì)象”壳快。與普通的全局對(duì)象不同的是,基于Vue數(shù)據(jù)與視圖綁定的特點(diǎn)镇草,當(dāng)store中的狀態(tài)發(fā)生變化時(shí)眶痰,與之綁定的視圖也會(huì)被重新渲染。
  • 渲染是一個(gè)單向的過程梯啤,因?yàn)閟tore中的狀態(tài)不允許被直接修改竖伯。
  • 改變store中的狀態(tài)的唯一途徑就是顯式的提交(commit)mutation,這可以讓我們方便的跟蹤每一個(gè)狀態(tài)的變化因宇。
1.2 什么數(shù)據(jù)才需要存儲(chǔ)到Vuex中七婴?
  • 一般情況下,只有組件之間共享的數(shù)據(jù)察滑,才有必要存儲(chǔ)到vuex(store)中打厘;
  • 對(duì)于組件中的私有數(shù)據(jù),依舊存儲(chǔ)在組件自身的data中即可贺辰。
1.3 使用Vuex統(tǒng)一管理的好處
  1. 能夠在vuex中集中管理共享的數(shù)據(jù)户盯,易于開發(fā)和后期的維護(hù)。
  2. 能夠高效的實(shí)現(xiàn)組件之間的數(shù)據(jù)共享魂爪,提高開發(fā)的效率先舷。
  3. 存儲(chǔ)在vuex中的數(shù)據(jù)都是響應(yīng)式的,能夠?qū)崟r(shí)保持?jǐn)?shù)據(jù)與頁面的同步滓侍。

二蒋川、Vuex核心概念

Vuex有5個(gè)重要的概念:StateGetter撩笆,Mutation捺球,Action缸浦,Module

1. State

State用于維護(hù)所有應(yīng)用層的狀態(tài)氮兵,并確保應(yīng)用只有唯一的數(shù)據(jù)源(SSOT裂逐,Single Source of Truth)。

  • 用法:
//創(chuàng)建store數(shù)據(jù)源泣栈,提供唯一公共數(shù)據(jù)
const store = new Vuex.Store({
  state: { 
      count: 0
     }
})

組件訪問State中數(shù)據(jù)的方式有兩種:

  1. this.$store.state.count
  2. mapState輔助函數(shù)映射下來
import { mapState } from 'vuex'
export default{
  computed: {
    ...mapState(['count']) //...是ES6中的對(duì)象展開運(yùn)算符
  }
}
2.Getter

Getter維護(hù)由State派生的一些狀態(tài)卜高,這些狀態(tài)隨著State狀態(tài)的變化而變化。

  1. 與計(jì)算屬性一樣南片,Getter中的派生狀態(tài)在被計(jì)算之后會(huì)被緩存起來掺涛。
  2. 當(dāng)重復(fù)調(diào)用時(shí),如果依賴的狀態(tài)沒有變化疼进,那么vuex不會(huì)重新計(jì)算派生狀態(tài)的值薪缆,而是直接采用緩存值。
  • 用法:
const store = new Vuex.Store({
  state: {
    count: 0
  },
  getters: {
    showNum (state) {//Vuex為其注入state對(duì)象
      return '當(dāng)前最新的數(shù)量是【'+ state.count +'】'
    }
  }
})

Getter有兩種使用方式:

  1. this.$store.getters.showNum
  2. 使用mapGetters輔助函數(shù)映射
import { mapGetters } from 'vuex'

export default {
  computed:{
    ...mapGetters{[ 'showNum']}
  }
}
3. Mutation

Mutation提供修改State狀態(tài)的方法伞广。

1.只能通過mutation變更Store數(shù)據(jù)拣帽,不可以直接操作Store中的數(shù)據(jù)
2.通過這種方式雖然操作起來稍微繁瑣一些,但是可以集中監(jiān)控所有數(shù)據(jù)的變化

  • 用法:
new Vuex.Store ({
  state : {
    count: 0
  },
  Mutations : {
    addCount (state, num){
      state.count += num || 1
    }
  }
})

mutations有兩種觸發(fā)方式:

  1. 使用store.commit來提交mutation
methods:{
  addCount () {
    this.$store.commit('addCount')
  }
}
  1. 使用mapMutations輔助函數(shù)映射
import { mapState,mapMutations } from 'vuex'
export default {
computed: {
    ...mapState(['count'])
  },
  methods: {
    ...mapMutations(['addCount']),
    ...mapMutations({ //為mutation賦別名嚼锄,注意沖突减拭,此方法不常用
      increaseCount: 'addCount' 
    })
  }
}
4. Action

Action用于處理異步任務(wù)。
Action類似于Mutation灾票,不同在

  1. Action不能直接修改狀態(tài)峡谊,只能通過提交mutation來修改
  2. Action可以包含異步操作
  • 用法:
new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    addCount (state, num){
      state.count += num || 1
    }
  },
  actions: {
    // context具有和store實(shí)例相同的屬性和方法
    // 可以通過context獲取state和getters中的值,或者提交mutation和分發(fā)其他的action
    addCountAsync(context, num){
      setTimeout(()=>{
        context.commit('addCountAsync', num || 1000)
      }, num || 1000)
    }
  }
})

Action也有兩種觸發(fā)方式:

  1. 使用store.dispatch來分發(fā)action
methods: {
  addCountAsync (num) {
    this.$store.dispatch('addCountAsync ', num)
  }
}
  1. 使用mapActions輔助函數(shù)映射
`import { mapState, mapActions } from 'vuex'`
export default{
  computed: {
    ...mapState(['count'])
  },
  methods: {
    ...mapActions([ 'addCountAsync']),
    ...mapActions({ // 為action賦別名刊苍,注意沖突既们,此方法不常用
      increaseCountAsync: 'addCountAsync'
    })
  }
}
5. Module

由于使用單一狀態(tài)樹,當(dāng)項(xiàng)目的狀態(tài)非常多時(shí)正什,store對(duì)象就會(huì)變得十分臃腫啥纸。
因此,Vuex允許我們將store分割成模塊(Module)婴氮,每個(gè)模塊擁有獨(dú)立的State斯棒、 Getter、 Mutation和Action主经,模塊之外還可以嵌套模塊荣暮,每一級(jí)都有著相同的結(jié)構(gòu)。

  • 用法:
//定義模塊
const counter = {
  namespaced: true, // 定義為獨(dú)立的命名空間
  state: {
    count: 0
  },
  getters: {
    // 在模塊中罩驻,計(jì)算方法還會(huì)具有 rootState穗酥、rootGetters參數(shù)以獲取根模塊中的數(shù)據(jù)
    tentimesCount (state, getters, rootState, rootGetters) {
      console.log(state, getters, rootState, rootGetters)
      return state.count * 10
    }
  },
  mutaions: {
    addCount (state, num) {
      state.count += num || 1
    }
  },
  actions: {
    // context具有和store實(shí)例相同的屬性和方法
    // 可以通過context獲取state和getters中的值,或者提交mutation和分發(fā)其他的action
    // 在模塊中,context還會(huì)具有 rootState砾跃、rootGetters參數(shù)以獲取根模塊中的數(shù)據(jù)
    addCountAsync (context, num) {
      setTimeout(()=>{
        context.commit('addCountAsync', num || 1000)
      }, num || 1000)
    }
  }
}

新建倉庫

new Vuex.store({
  modules: { // 注冊模塊
    counter
  }
})

在組件中骏啰,模塊的使用方法如下:

import {mapState, mapGetters, mapMutations , mapActions } from 'vuex'
export default {
  computed: {
    //輔助函數(shù)的第一個(gè)參數(shù)為模塊的名稱
    ...mapState('counter', ['count'])
    ...mapGetters('counter', ['tenTimesCount'])
  },
  methods: {
    ...mapMutations('counter', ['addCount'])
    ...mapActions('counter', ['addCountAsync'])
  }
}

【總結(jié)】
作為一個(gè)狀態(tài)管理器,首先要有保管狀態(tài)的容器——State抽高;
為了滿足衍生數(shù)據(jù)和數(shù)據(jù)鏈的需求判耕,從而有了Getter
為了可以“顯式地”修改狀態(tài)翘骂,所以需要Mutation壁熄;
為了可以“異步地”修改狀態(tài)(滿足AJAX等異步數(shù)據(jù)交互),所以需要Action碳竟;
最后请毛,如果應(yīng)用有成百上千個(gè)狀態(tài),放在一起會(huì)顯得十分龐雜瞭亮,所以需要分模塊管理(Module)。

三固棚、在項(xiàng)目中使用Vuex

  1. 安裝插件
    npm install vuex --save-dev 或者 cnpm install vuex --save-dev
    使用npm或者cnpm都可以
  2. 創(chuàng)建文件
    在src目錄下創(chuàng)建store统翩、store/index.jsstore/modules此洲、store/modules/counter.js
    其中厂汗,
    store是我們進(jìn)行Vuex倉庫開發(fā)的工作目錄,
    store/index.js是倉庫的輸出文件呜师,
    store/modules目錄用于放置各個(gè)模塊娶桦,
    store/modules/counter.js文件是一個(gè)加數(shù)器模塊。
    • store/modules/counter.js中的代碼如下:
    export default {
      namespaced: true, // 定義為獨(dú)立的命名空間
      state: {
        count: 0
      },
      getters: {
        // 在模塊中汁汗,計(jì)算方法還會(huì)具有 rootState衷畦、rootGetters參數(shù)以獲取根模塊中的數(shù)據(jù)
        tentimesCount (state, getters, rootState, rootGetters) {
          console.log(state, getters, rootState, rootGetters)
          return state.count * 10
        }
      },
      mutaions: {
        addCount (state, num) {
          state.count += num || 1
        }
      },
      actions: {
        // context具有和store實(shí)例相同的屬性和方法
        // 可以通過context獲取state和getters中的值,或者提交mutation和分發(fā)其他的action
        // 在模塊中知牌,context還會(huì)具有 rootState祈争、rootGetters參數(shù)以獲取根模塊中的數(shù)據(jù)
        addCountAsync (context, num) {
          setTimeout(()=>{
            context.commit('addCountAsync', num || 1000)
          }, num || 1000)
        }
      }
    }
    
    • store/index.js中的代碼如下:
    import Vue from 'vue'
    import Vuex from 'vuex'
    import counter from './modules/counter' //引入加數(shù)器模塊
    
    Vue.use(Vuex) //安裝插件
    
    export default new Vuex.Store {( //實(shí)例化Vuex倉庫
      modules: {
        counter
      }
    )}
    
    上面已經(jīng)實(shí)例化了一個(gè)Vuex倉庫并構(gòu)建了一個(gè)加數(shù)器模塊。之后角寸,我們要在Vue實(shí)例中引入這個(gè)倉庫菩混,這還需要修改兩個(gè)文件: webpack的入口文件main.js和單組件文件 components/HelloWorld.vue.
    • 修改后的main.js的代碼如下:
    import Vue from 'vue'
    import App from './App'
    import router from './router' 
    import store from './store'
    
    Vue.config.productionTip = false
    
    new Vue({
      el: #app,
      router,
      store,
      components: {App},
      template: '<App/>'
    })
    
    到此就已經(jīng)將倉庫注冊到了Vue實(shí)例中了,之后就可以在項(xiàng)目的任意文件中使用了扁藕。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沮峡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子亿柑,更是在濱河造成了極大的恐慌邢疙,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異秘症,居然都是意外死亡照卦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門乡摹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來役耕,“玉大人,你說我怎么就攤上這事聪廉∷捕唬” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵板熊,是天一觀的道長框全。 經(jīng)常有香客問我,道長干签,這世上最難降的妖魔是什么津辩? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮容劳,結(jié)果婚禮上喘沿,老公的妹妹穿的比我還像新娘。我一直安慰自己竭贩,他們只是感情好蚜印,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著留量,像睡著了一般窄赋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上楼熄,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天忆绰,我揣著相機(jī)與錄音,去河邊找鬼可岂。 笑死较木,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的青柄。 我是一名探鬼主播伐债,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼致开!你這毒婦竟也來了峰锁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤双戳,失蹤者是張志新(化名)和其女友劉穎虹蒋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡魄衅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年峭竣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晃虫。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡皆撩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哲银,到底是詐尸還是另有隱情扛吞,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布荆责,位于F島的核電站滥比,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏做院。R本人自食惡果不足惜盲泛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望键耕。 院中可真熱鬧查乒,春花似錦、人聲如沸郁竟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棚亩。三九已至,卻和暖如春虏杰,著一層夾襖步出監(jiān)牢的瞬間讥蟆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工纺阔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘸彤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓笛钝,卻偏偏與公主長得像质况,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子玻靡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

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