Vuex

什么是Vuex及Vuex的優(yōu)缺點(diǎn)

Vuex是專為Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理模式阿弃。比如一個(gè)簡(jiǎn)單的Vue計(jì)數(shù)應(yīng)用:

new Vue({
  // state
  data () {
    return {
      count: 0
    }
  },
  // view
  template: `
    <div>{{ count }}</div>
  `,
  // actions
  methods: {
    increment () {
      this.count++
    }
  }
})

這個(gè)狀態(tài)自管理應(yīng)用包含以下三部分:
· state贴唇,驅(qū)動(dòng)應(yīng)用的數(shù)據(jù)源
· view,以聲明方式將state映射到視圖
· actions豌拙,響應(yīng)在view上的用戶輸入導(dǎo)致的狀態(tài)變化
對(duì)于如下圖所示的單向數(shù)據(jù)流:

image.png

當(dāng)遇到多個(gè)組件共享狀態(tài)的時(shí)候,其簡(jiǎn)潔性很容易被破壞:
· 多個(gè)視圖依賴于同一狀態(tài)
· 來自不同視圖的行為需要變更同一狀態(tài)
所以,可以把組件的共享狀態(tài)抽取出來胡嘿,以一個(gè)全局單例模式管理,在這種模式下钳踊,組件樹構(gòu)成了一個(gè)巨大的“視圖”衷敌,不管在樹的哪個(gè)位置,任何組件都能獲取狀態(tài)或觸發(fā)行為拓瞪。Vuex便由此而生缴罗。

Vuex的優(yōu)缺點(diǎn)

Vuex可以幫助管理共享狀態(tài),對(duì)開發(fā)大型單頁應(yīng)用帶來了方便祭埂。但如果要開發(fā)的應(yīng)用足夠簡(jiǎn)單面氓,Vuex可能就顯得相對(duì)繁瑣冗余,不適合使用。

Vuex五大屬性

Vuex的五大屬性分別是:state侧但、getter矢空、mutation、action禀横、module
根據(jù)我個(gè)人的理解屁药,可以把Vuex與Vue組件進(jìn)行對(duì)照記憶:
**state => 基本數(shù)據(jù) => data
getters => 從基本數(shù)據(jù)派生的數(shù)據(jù) => computed
mutations => 提交更改數(shù)據(jù)的方法,同步柏锄! => 同步methods
actions => 像一個(gè)裝飾器酿箭,包裹mutations,使之可以異步趾娃。 => 異步調(diào)用methods
modules => 模塊化Vuex

1. state

2. getter

3. mutation

4. action

5. module

module是考慮到使用單一狀態(tài)樹缭嫡,當(dāng)所有狀態(tài)集中到一個(gè)比較大的對(duì)象時(shí),如果應(yīng)用變得非常復(fù)雜抬闷, 那么store對(duì)象就可能變得相當(dāng)臃腫妇蛀,不便于開發(fā)與維護(hù)。
Vuex允許將store分割成多個(gè)模塊(module)笤成,每個(gè)模塊都擁有自己的state评架、mutation、action炕泳、getter纵诞,甚至能嵌套子模塊(module)。
注意:moduleX的聲明必須在store之前培遵。

const moduleA = {
    state: {
        count: 3
    },
    mutations: {
        increment(state) {
            state.count++
        }
    },
    getters: {
      sumWithRootCount (state, getters, rootState) {
        return state.count + rootState.count
     }
    },
    actions: {
        incrementIfOddOnRootSum({state, commit, rootState}){
            if((state.count + rootState.count) % 2 === 1){
                commit('increment')
            }
        }
    }
}

const moduleB = {
    state: {
        count: 8
    },
    mutations: {
        login() {}
    },
    getters: {
        login() {}
    },
    actions: {
        login() {}
    }
}

const store = new Vuex.Store({
    modules: {
        a: moduleA,
        b: moduleB
    },
    state: {
        count: 2
    },
    mutations: {
        increment(state) {
            state.count++
        }
    },
    actions: {

    },
    getters: {

    }
})

new Vue({
    el: '#app',
    store,
    data: {

    },
    computed: {

    }
});

對(duì)于模塊內(nèi)部的mutation和getter浙芙,接收的第一個(gè)參數(shù)是模塊的局部state,如moduleA的mutation與getter籽腕。
對(duì)于模塊內(nèi)部的action嗡呼,局部state通過'context.state暴露出來,根節(jié)點(diǎn)狀態(tài)則通過context.rootState暴露出來节仿。如moduleA中的action晤锥。 對(duì)于模塊內(nèi)部的getter掉蔬,根節(jié)點(diǎn)state則作為第三個(gè)參數(shù)暴露出來廊宪。如moduleA中的getter。 **命名空間** 默認(rèn)情況下女轿,模塊內(nèi)部的action箭启、mutation、getter是注冊(cè)在全局命名空間的蛉迹,即假如你定義的moduleA與store都有increment()的mutation屬性傅寡,那當(dāng)你執(zhí)行:store.commit('increment')`的時(shí)候,會(huì)將store與其子模塊里mutation的increment方法一起調(diào)用。如:

console.log(store.state.a.count); // 3
console.log(store.state.count); // 2
store.commit('increment');
console.log(store.state.a.count); // 4
console.log(store.state.count); // 3

如果你希望定義的模塊有更高的封裝度和復(fù)用性荐操,可以通過加入namespaced: true的方式使其成為帶命名空間的模塊芜抒。當(dāng)模塊被注冊(cè)后,其所有的getter托启、action與mutation都會(huì)自動(dòng)根據(jù)模塊注冊(cè)的路徑調(diào)整命名宅倒。
例如給moduleA添加namespaced: true,則執(zhí)行store.commit('increment')時(shí)會(huì)自動(dòng)跳過moduleA屯耸。此時(shí):

const moduleA = {
    namespaced: true
......
......
}

console.log(store.state.a.count); // 3
console.log(store.state.count); // 2
store.commit('increment');
console.log(store.state.a.count); // 3
console.log(store.state.count); // 3

此時(shí)若想執(zhí)行moduleA的increment拐迁,則要這樣寫:store.commit('a/increment'),這樣便只執(zhí)行moduleA中的increment疗绣。
若moduleA嵌套moduleC线召,則在不聲明moduleC的namespaced情況下,其繼承父模塊moduleA的命名空間多矮。即:

const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,

      // 模塊內(nèi)容(module assets)
      state: { ... }, // 模塊內(nèi)的狀態(tài)已經(jīng)是嵌套的了缓淹,使用 `namespaced` 屬性不會(huì)對(duì)其產(chǎn)生影響
      getters: {
        isAdmin () { ... } // -> getters['account/isAdmin']
      },
      actions: {
        login () { ... } // -> dispatch('account/login')
      },
      mutations: {
        login () { ... } // -> commit('account/login')
      },

      // 嵌套模塊
      modules: {
        // 繼承父模塊的命名空間
        myPage: {
          state: { ... },
          getters: {
            profile () { ... } // -> getters['account/profile']
          }
        },

        // 進(jìn)一步嵌套命名空間
        posts: {
          namespaced: true,

          state: { ... },
          getters: {
            popular () { ... } // -> getters['account/posts/popular']
          }
        }
      }
    }
  }
})

在帶命名空間的模塊內(nèi)訪問全局內(nèi)容
對(duì)于getter,會(huì)將rootState與rootGetters作為第三與第四參數(shù)傳入:

    getters: {
        someGetter (state, getters, rootState, rootGetters) {
            rootState.count;
            state.count;
            
            getters.someOtherGetter;
            rootGetters.someOtherGetter;
        }
    },

對(duì)于mutation與action塔逃,將(root: true}作為第三參數(shù)傳給dispatch或commit即可:

    actions: {
        someAction({ dispatch, commit, getters, rootGetters }) {
            getters.someGetter;
            rootGetters.someGetter;
            
            dispatch('someOtherAction'); // 不傳第三參數(shù)割卖,則從自身查找
            dispatch('someOtherAction', null, { root: true }); // 傳入第三參數(shù),則從父模塊查找
            
            commit('someMutation'); // 與上同理
            commit('someMutation', null, { root: true });
        }
    }

那么對(duì)于mapState患雏、mapGetters鹏溯、mapMutations、mapActions這些函數(shù)來綁定帶命名空間的模塊時(shí)淹仑,直接寫可能有點(diǎn)繁瑣:

computed: {
  ...mapState({
    a: state => state.some.nested.module.a,
    b: state => state.some.nested.module.b
  })
},
methods: {
  ...mapActions([
    'some/nested/module/foo', // -> this['some/nested/module/foo']()
    'some/nested/module/bar' // -> this['some/nested/module/bar']()
  ])
}

可以將模塊的空間名稱字符串作為第一個(gè)參數(shù)傳遞給上述函數(shù)丙挽,這樣所有綁定都會(huì)自動(dòng)將該模塊作為上下文。上面的例子可以簡(jiǎn)化為:

computed: {
  ...mapState('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module', [
    'foo', // -> this.foo()
    'bar' // -> this.bar()
  ])
}

模塊動(dòng)態(tài)注冊(cè)
你可以在store創(chuàng)建之后匀借,動(dòng)態(tài)地用store.registerModule方法給store創(chuàng)建模塊:

// 注冊(cè)模塊 `myModule`
store.registerModule('myModule', {
  // ...
})
// 注冊(cè)嵌套模塊 `nested/myModule`
store.registerModule(['nested', 'myModule'], {
  // ...
})

之后就能通過store,state.myModulestore.state.nested.myModule來訪問模塊的狀態(tài)颜阐。你也可以使用 store.unregisterModule(moduleName)來動(dòng)態(tài)卸載模塊。但需要注意吓肋,你不可以卸載store聲明時(shí)的模塊凳怨,即靜態(tài)模塊。
保留state
在注冊(cè)新module時(shí)是鬼,如果你想保留過去的state肤舞,例如從服務(wù)器渲染的應(yīng)用保留state,可以通過preserveState選項(xiàng)將其歸檔store.registerModule('a', module, { preserveState: true })均蜜。
當(dāng)你設(shè)置 preserveState: true 時(shí)李剖,該模塊會(huì)被注冊(cè),action囤耳、mutation 和 getter 會(huì)被添加到 store 中篙顺,但是 state 不會(huì)偶芍。這里假設(shè) store 的 state 已經(jīng)包含了這個(gè) module 的 state 并且你不希望將其覆寫。
模塊重用
在實(shí)際開發(fā)中可能會(huì)有一個(gè)store中多次注冊(cè)同一個(gè)模塊德玫,或者多個(gè)store注冊(cè)同一個(gè)模塊的需求匪蟀,此時(shí)module被引用調(diào)用一次,其state就可能被重寫宰僧,導(dǎo)致store或模塊間數(shù)據(jù)互相污染萄窜。(類似于Vue組件內(nèi)的data會(huì)遇到同樣的問題)
解決辦法也類似,就是使用一個(gè)函數(shù)來聲明模塊狀態(tài):

const MyReusableModule = {
  state () {
    return {
      foo: 'bar'
    }
  },
  // mutation, action 和 getter 等等...
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末撒桨,一起剝皮案震驚了整個(gè)濱河市查刻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凤类,老刑警劉巖穗泵,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谜疤,居然都是意外死亡佃延,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門夷磕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來履肃,“玉大人,你說我怎么就攤上這事坐桩〕咂澹” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵绵跷,是天一觀的道長(zhǎng)膘螟。 經(jīng)常有香客問我,道長(zhǎng)碾局,這世上最難降的妖魔是什么荆残? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮净当,結(jié)果婚禮上内斯,老公的妹妹穿的比我還像新娘。我一直安慰自己像啼,他們只是感情好俘闯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著埋合,像睡著了一般备徐。 火紅的嫁衣襯著肌膚如雪萄传。 梳的紋絲不亂的頭發(fā)上甚颂,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音振诬,去河邊找鬼蹭睡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛赶么,可吹牛的內(nèi)容都是我干的辫呻。 我是一名探鬼主播放闺,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼篡悟,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼搬葬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起艳悔,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤急凰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后猜年,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體香府,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年码倦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了企孩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡袁稽,死狀恐怖勿璃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情推汽,我是刑警寧澤补疑,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站歹撒,受9級(jí)特大地震影響莲组,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜暖夭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一锹杈、第九天 我趴在偏房一處隱蔽的房頂上張望撵孤。 院中可真熱鬧,春花似錦竭望、人聲如沸邪码。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闭专。三九已至,卻和暖如春旧烧,著一層夾襖步出監(jiān)牢的瞬間影钉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國打工掘剪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斧拍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓杖小,卻偏偏與公主長(zhǎng)得像肆汹,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子予权,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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

  • ### store 1. Vue 組件中獲得 Vuex 狀態(tài) ```js //方式一 全局引入單例類 // 創(chuàng)建一...
    蕓豆_6a86閱讀 730評(píng)論 0 3
  • 安裝 npm npm install vuex --save 在一個(gè)模塊化的打包系統(tǒng)中昂勉,您必須顯式地通過Vue.u...
    蕭玄辭閱讀 2,937評(píng)論 0 7
  • 前言 之前幾篇解析 Vue 源碼的文章都是完整的分析整個(gè)源碼的執(zhí)行過程,這篇文章我會(huì)將重點(diǎn)放在核心原理的解析扫腺,不會(huì)...
    心_c2a2閱讀 1,469評(píng)論 1 8
  • import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(V...
    F_imok閱讀 2,647評(píng)論 0 12
  • 這是和小伙伴在武漢大學(xué)的學(xué)舍拍的照片岗照,最簡(jiǎn)單的解釋就是我的先輩曾在這里讀書,我的族人曾在這里居住笆环。 一直好奇自己的...
    快樂神仙鼠閱讀 440評(píng)論 0 0