教你使用 Vuex亡笑,從0到1侣夷,進階開始

第一步,了解Vuex

??想象一個場景
如果你的項目里有很多頁面(組件/視圖)仑乌,頁面之間存在多級的嵌套關系百拓,此時琴锭,這些頁面假如都需要共享一個狀態(tài)的時候,此時就會產(chǎn)生以下兩個問題:

多個視圖依賴同一個狀態(tài)
來自不同視圖的行為需要變更同一個狀態(tài)
?? 動動你的小腦袋你就會想到解決以上方法的方案:
對于第一個問題耐版,假如是多級嵌套關系祠够,你可以使用父子組件傳參進行解決,雖有些麻煩粪牲,但好在可以解決古瓤;對于兄弟組件或者關系更復雜組件之間,就很難辦了腺阳,雖然可以通過各種各樣的辦法解決落君,可實在很不優(yōu)雅,而且等項目做大了亭引,代碼就會變成屎山绎速,實在令人心煩。
對于第二個問題焙蚓,你可以通過父子組件直接引用纹冤,或者通過事件來變更或者同步狀態(tài)的多份拷貝,這種模式很脆弱购公,往往使得代碼難以維護萌京,而且同樣會讓代碼變成屎山。
?? 此時宏浩,既然思考到了這里知残,如果換一種思路呢:
把各個組件都需要依賴的同一個狀態(tài)抽取出來,在全局使用單例模式進行管理比庄。
在這種模式下求妹,任何組件都可以直接訪問到這個狀態(tài),或者當狀態(tài)發(fā)生改變時佳窑,所有的組件都獲得更新制恍。
?? 這時候,Vuex誕生了神凑!
這就是 Vuex 背后的基本思想吧趣,借鑒了 Flux、Redux耙厚。與其他模式不同的是强挫,Vuex 是專門為 Vue 設計的狀態(tài)管理庫,以利用 Vue.js 的細粒度數(shù)據(jù)響應機制來進行高效的狀態(tài)更新薛躬。


圖片

第二步俯渤,安裝

進入項目,在命令行中輸入安裝指令型宝,回車

npm install vuex --save

然后配置 vuex八匠,使其工作起來:在src路徑下創(chuàng)建store文件夾絮爷,然后創(chuàng)建index.js文件,文件內(nèi)容如下:

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        // 定義一個name梨树,以供全局使用
        name: '張三',
        // 定義一個number坑夯,以供全局使用
        number: 0,
        // 定義一個list,以供全局使用
        list: [
            { id: 1, name: '111' },
            { id: 2, name: '222' },
            { id: 3, name: '333' },
        ]
    },
});

export default store;

修改main.js:

import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store'; // 引入我們前面導出的store對象

Vue.config.productionTip = false;

new Vue({
    el: '#app',
    router,
    store, // 把store對象添加到vue實例上
    components: { App },
    template: '<App/>'
});

最后修改App.vue:

<template>
    <div></div>
</template>

<script>
    export default {
        mounted() {
            // 使用this.$store.state.XXX可以直接訪問到倉庫中的狀態(tài)
            console.log(this.$store.state.name); 
        }
    }
</script>

此時抡四,啟動項目npm run dev柜蜈,即可在控制臺輸出剛才我們定義在store中的name的值。

圖片
  • ?? 官方建議1:

官方建議我們以上操作this.$store.state.XXX最好放在計算屬性中指巡,當然淑履,我也建議你這么使用,這樣可以讓你的代碼看起來更優(yōu)雅一些藻雪,就像這樣:

<script>
import { mapState } from 'vuex'; // 從vuex中導入mapState
export default {
    mounted() {
        console.log(this.name);
    },
    computed: {
        ...mapState(['name']), // 經(jīng)過解構后秘噪,自動就添加到了計算屬性中,此時就可以直接像訪問計算屬性一樣訪問它
    },
}
</script>

你甚至可以在解構的時候給它賦別名勉耀,取外號指煎,就像這樣:

...mapState({ aliasName: 'name' }),  // 賦別名的話,這里接收對象便斥,而不是數(shù)組

?? 至此至壤,安裝vuex并且初始化的工作就結束了,此時你可以很輕易的在項目的任意地方訪問到倉庫里的狀態(tài)

第三步椭住,了解修飾器:Getter

當你看到這里的時候崇渗,證明你上一步已經(jīng)完美的創(chuàng)建好一個vue項目字逗,并且將vuex安裝了進去京郑!

好!接下來葫掉,我們介紹一個讀取操作的 “修飾利器” ---Getter

?? 設想一個場景些举,你已經(jīng)將store中的name展示到頁面上了,而且是很多頁面都展示了俭厚,此時產(chǎn)品經(jīng)理過來找事兒??:

產(chǎn)品經(jīng)理:所有的name前面都要加上“hello”户魏!

我:為什么?

產(chǎn)品經(jīng)理:我提需求還需要為什么嗎挪挤?

我:好叼丑,我加!

這時候扛门,你第一想到的是怎么加呢鸠信,emm...在每個頁面上,使用this.$store.state.name獲取到值之后论寨,進行遍歷星立,前面追加"hello"即可爽茴。

????♂? 錯!這樣很不好绰垂,原因如下:

第一室奏,假如你在A、B劲装、C三個頁面都用到了name胧沫,那么你要在這A、B酱畅、C三個頁面都修改一遍琳袄,多個頁面你就要加很多遍這個方法,造成代碼冗余纺酸,很不好窖逗;
第二,假如下次產(chǎn)品經(jīng)理讓你把 “hello” 改成 “fuck” 的時候餐蔬,你又得把三個頁面都改一遍碎紊,這時候你只能抽自己的臉了...
???? 吸取上面的教訓,你會有一個新的思路:我們可以直接在store中對name進行一些操作或者加工樊诺,從源頭解決問題仗考!那么具體應該怎么寫呢?這時候词爬,本次將要介紹的這個Getter利器閃亮登場秃嗜!

?? 怎么用呢?不廢話顿膨,show code锅锨!

首先,在store對象中增加getters屬性

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        name: '張三',
        number: 0,
        list: [
            { id: 1, name: '111' },
            { id: 2, name: '222' },
            { id: 3, name: '333' },
        ]
    },
    // 在store對象中增加getters屬性
    getters: {
        getMessage(state) { // 獲取修飾后的name恋沃,第一個參數(shù)state為必要參數(shù)必搞,必須寫在形參上
            return `hello${state.name}`;
        }
    },
});

export default store;

在組件中使用:

export default {
    mounted() {
        // 注意不是$store.state了,而是$store.getters
        console.log(this.$store.state.name);
        console.log(this.$store.getters.getMessage);
    }
}

然后查看控制臺:

圖片

沒有問題的

?? 官方建議:是不是每次都寫this.$store.getters.XXX讓你感到厭煩囊咏,你實在不想寫這個東西怎么辦恕洲,當然有解決方案,官方建議我們可以使用mapGetters去解構到計算屬性中梅割,就像使用mapState一樣霜第,就可以直接使用this調用了,就像下面這樣:

<script>
import { mapState, mapGetters } from 'vuex';
export default {
    mounted() {
        console.log(this.name);
        console.log(this.getMessage);
    },
    computed: {
        ...mapState(['name']),
        ...mapGetters(['getMessage']),
    },
}
</script>

此時可以得到和之前一樣的效果户辞。

當然泌类,和mapState一樣你也可以取別名,取外號咆课,就像下面這樣:

...mapGetters({ aliasName: 'getMessage' }),  // 賦別名的話末誓,這里接收對象扯俱,而不是數(shù)組

?? OK,當你看到這里喇澡,你已經(jīng)成功的把Getter用起來了迅栅,你也能明白在什么時候應該用到getters,你可以通過計算屬性訪問(緩存)晴玖,也可以通過方法訪問(不緩存)读存,你甚至可以在getters的方法里面再調用getters方法,當然你也實現(xiàn)了像state那樣呕屎,使用mapGetters解構到計算屬性中让簿,這樣你就可以很方便的使用getters啦!

?? 讀取值的操作我們有 “原生讀(state)” 和 “修飾讀(getters)”秀睛,接下來就要介紹怎么修改值了尔当!

第四步,了解如何修改值:Mutation

?? OK蹂安!首先恭喜你看到了這里椭迎,至此,我們已經(jīng)成功訪問到了store里面的值田盈,接下來我來介紹一下怎么修改state里面的值畜号。

說到修改值,有的同學就會想到這樣寫:

// 錯誤示范
this.$store.state.XXX = XXX;

?? 首先允瞧,這里我先明確的說明:這是錯誤的寫法简软!這是錯誤的寫法!這是錯誤的寫法述暂!

為什么上面是錯誤的寫法痹升?因為這個store倉庫比較奇怪,你可以隨便拿贸典,但是你不能隨便改视卢,我舉個例子:

?? 假如你打開微信朋友圈踱卵,看到你的好友發(fā)了動態(tài)廊驼,但是動態(tài)里有個錯別字,你要怎么辦呢惋砂?你可以幫他改掉嗎妒挎?當然不可以!我們只能通知他本人去修改西饵,因為是別人的朋友圈酝掩,你是無權操作的,只有他自己才能操作眷柔,同理期虾,在vuex中原朝,我們不能直接修改倉庫里的值,必須用vuex自帶的方法去修改镶苞,這個時候喳坠,Mutation閃亮登場了!

?? 把問題解釋清楚之后茂蚓,我們準備完成一個效果:我們先輸出state中的number的默認值0壕鹉,然后我們在vue組件里通過提交Mutations改變number的默認值0,改成我們想修改的值聋涨,然后再輸出出來晾浴,這樣就可以簡單練習怎么使用Mutations了。不說廢話牍白,上代碼脊凰。

修改store/index.js

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        name: '張三',
        number: 0,
    },
    mutations: { // 增加nutations屬性
        setNumber(state) {  // 增加一個mutations的方法,方法的作用是讓num從0變成5茂腥,state是必須默認參數(shù)
            state.number = 5;
        }
    },
});

export default store;

修改App.vue

<script>
export default {
    mounted() {
        console.log(`舊值:${this.$store.state.number}`);
        this.$store.commit('setNumber');
        console.log(`新值:${this.$store.state.number}`);
    },
}
</script>
  • 運行項目笙各,查看控制臺:
圖片
  • ?? 以上是簡單實現(xiàn)mutations的方法,是沒有傳參的础芍,如果我們想傳不固定的參數(shù)怎么辦杈抢?接下來教你解決

  • 修改store/index.js

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        name: '張三',
        number: 0,
    },
    mutations: {
        setNumber(state) {
            state.number = 5;
        },
        setNumberIsWhat(state, number) { // 增加一個帶參數(shù)的mutations方法
            state.number = number;
        },
    },
});

export default store;

修改App.vue

<script>
export default {
    mounted() {
        console.log(`舊值:${this.$store.state.number}`);
        this.$store.commit('setNumberIsWhat', 666);
        console.log(`新值:${this.$store.state.number}`);
    },
}
</script>
  • 運行項目,查看控制臺:
圖片

沒有問題仑性!

  • 注意:上面的這種傳參的方式雖然可以達到目的惶楼,但是并不推薦,官方建議傳遞一個對象進去诊杆,這樣看起來更美觀歼捐,對象的名字你可以隨意命名,但我們一般命名為payload晨汹,代碼如下:

  • 修改store/index.js

mutations: {
    setNumber(state) {
        state.number = 5;
    },
    setNumberIsWhat(state, payload) { // 增加一個帶參數(shù)的mutations方法豹储,并且**官方建議**payload為一個對象
        state.number = payload.number;
    },
},

修改App.vue

<script>
export default {
    mounted() {
        console.log(`舊值:${this.$store.state.number}`);
        this.$store.commit('setNumberIsWhat', { number: 666 });  // 調用的時候也需要傳遞一個對象
        console.log(`新值:${this.$store.state.number}`);
    },
}
</script>

此時可以得到和之前一樣的效果,并且代碼更加美觀淘这!
?? 這里說一條重要原則:Mutations里面的函數(shù)必須是同步操作剥扣,不能包含異步操作!(別急铝穷,后面會講到異步)

?? 這里說一條重要原則:Mutations里面的函數(shù)必須是同步操作钠怯,不能包含異步操作!(別急曙聂,后面會講到異步)

?? 這里說一條重要原則:Mutations里面的函數(shù)必須是同步操作晦炊,不能包含異步操作!(別急,后面會講到異步)

好的断国,記住這個重要原則贤姆,我們再說一個小技巧:

?? 官方建議:就像最開始的mapState和mapGetters一樣,我們在組件中可以使用mapMutations以代替this.$store.commit('XXX')稳衬,是不是很方便呢庐氮?

<script>
import { mapMutations } from 'vuex';
export default {
    mounted() {
        this.setNumberIsWhat({ number: 999 });
    },
    methods: {   // 注意,mapMutations是解構到methods里面的宋彼,而不是計算屬性了
        ...mapMutations(['setNumberIsWhat']),
    },
}
</script>

此時可以得到和之前一樣的效果弄砍,并且代碼又美觀了一點扔傅!

當然你也可以給它叫別名蒜撮,取外號组题,就像這樣:

methods:{
    ...mapMutations({ setNumberIsAlias: 'setNumberIsWhat' }),   // 賦別名的話先紫,這里接收對象舵匾,而不是數(shù)組
}

?? OK盐肃,關于Mutation的介紹大致就是這樣帚屉,另外你也掌握了在定義mutations方法的時候有無參數(shù)應該怎么寫渤愁;并且聽取了官方建議檐什,使用mapMutations解構到你的組件內(nèi)部的methods里碴卧,這樣你就可以很簡單的使用mutations方法啦!

?? 上面提到乃正,Mutations只能進行同步操作住册,所以,我們馬上開始下一節(jié)瓮具,看看使用Actions進行異步操作的時候應該注意什么荧飞!

第五步,了解異步操作:Actions

?? OK名党!本節(jié)我們來學習使用Actions叹阔,Actions存在的意義是假設你在修改state的時候有異步操作,vuex作者不希望你將異步操作放在Mutations中传睹,所以就給你設置了一個區(qū)域耳幢,讓你放異步操作,這就是Actions

?? 我們直接上一個代碼

修改store/index.js

const store = new Vuex.Store({
    state: {
        name: '張三',
        number: 0,
    },
    mutations: {
        setNumberIsWhat(state, payload) {
            state.number = payload.number;
        },
    },
    actions: {   // 增加actions屬性
        setNum(content) {  // 增加setNum方法欧啤,默認第一個參數(shù)是content睛藻,其值是復制的一份store
            return new Promise(resolve => {  // 我們模擬一個異步操作,1秒后修改number為888
                setTimeout(() => {
                    content.commit('setNumberIsWhat', { number: 888 });
                    resolve();
                }, 1000);
            });
        }
    }
});

修改App.vue

async mounted() {
    console.log(`舊值:${this.$store.state.number}`);
    await this.$store.dispatch('setNum');
    console.log(`新值:${this.$store.state.number}`);
},
  • 運行項目堂油,查看控制臺:
圖片

?? 看了例子修档,是不是明白了碧绞,action就是去提交mutation的府框,什么異步操作都在action中消化了,最后再去提交mutation的。

?? 當然迫靖,你可以模仿mutation進行傳參院峡,就像下面這樣:

  • 修改store/index.js
actions: {
    setNum(content, payload) {   // 增加payload參數(shù)
        return new Promise(resolve => {
            setTimeout(() => {
                content.commit('setNumberIsWhat', { number: payload.number });
                resolve();
            }, 1000);
        });
    },
}

修改App.vue

async mounted() {
    console.log(`舊值:${this.$store.state.number}`);
    await this.$store.dispatch('setNum', { number: 611 });
    console.log(`新值:${this.$store.state.number}`);
},
  • 運行項目,查看控制臺
圖片

沒有任何問題系宜!

  • ?? 官方建議1:你如果不想一直使用this.$store.dispatch('XXX')這樣的寫法調用action照激,你可以采用mapActions的方式,把相關的actions解構到methods中盹牧,用this直接調用:
<script>
import { mapActions } from 'vuex';
export default {
    methods: {
        ...mapActions(['setNum']),   // 就像這樣俩垃,解構到methods中
    },
    async mounted() {
        await this.setNum({ number: 123 });  // 直接這樣調用即可
    },
}
</script>

當然,你也可以取別名汰寓,取外號口柳,就像下面這樣:

...mapActions({ setNumAlias: 'setNum' }),   // 賦別名的話,這里接收對象有滑,而不是數(shù)組

?? 官方建議2:在store/index.js中的actions里面跃闹,方法的形參可以直接將commit解構出來,這樣可以方便后續(xù)操作:

actions: {
    setNum({ commit }) {   // 直接將content結構掉毛好,解構出commit望艺,下面就可以直接調用了
        return new Promise(resolve => {
            setTimeout(() => {
                commit('XXXX');  // 直接調用
                resolve();
            }, 1000);
        });
    },
},

?? OK,看到這里肌访,你應該明白action在vuex的位置了吧找默,什么時候該用action,什么時候不用它吼驶,你肯定有了自己的判斷啡莉,最主要的判斷條件就是我要做的操作是不是異步,這也是action存在的本質旨剥。當然咧欣,你不要將action和mutation混為一談,action其實就是mutation的上一級轨帜,在action這里處理完異步的一些操作后魄咕,后面的修改state就交給mutation去做了。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蚌父,一起剝皮案震驚了整個濱河市哮兰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苟弛,老刑警劉巖喝滞,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異膏秫,居然都是意外死亡右遭,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窘哈,“玉大人吹榴,你說我怎么就攤上這事」鐾瘢” “怎么了图筹?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長让腹。 經(jīng)常有香客問我远剩,道長,這世上最難降的妖魔是什么骇窍? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任民宿,我火速辦了婚禮,結果婚禮上像鸡,老公的妹妹穿的比我還像新娘活鹰。我一直安慰自己,他們只是感情好只估,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布志群。 她就那樣靜靜地躺著,像睡著了一般蛔钙。 火紅的嫁衣襯著肌膚如雪锌云。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天吁脱,我揣著相機與錄音桑涎,去河邊找鬼。 笑死兼贡,一個胖子當著我的面吹牛攻冷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播遍希,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼等曼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了凿蒜?” 一聲冷哼從身側響起禁谦,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎废封,沒想到半個月后州泊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡漂洋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年遥皂,在試婚紗的時候發(fā)現(xiàn)自己被綠了力喷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡渴肉,死狀恐怖冗懦,靈堂內(nèi)的尸體忽然破棺而出爽冕,到底是詐尸還是另有隱情仇祭,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布颈畸,位于F島的核電站乌奇,受9級特大地震影響,放射性物質發(fā)生泄漏眯娱。R本人自食惡果不足惜礁苗,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望徙缴。 院中可真熱鬧试伙,春花似錦、人聲如沸于样。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽穿剖。三九已至蚤蔓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間糊余,已是汗流浹背秀又。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贬芥,地道東北人吐辙。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像蘸劈,于是被迫代替她去往敵國和親袱讹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

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

  • 基礎入門文檔建議直接查看vuex中文文檔vuex中文文檔 我的理解:在 Vue.js 的項目中昵时,如果項目結構簡單捷雕,...
    阿爾法乀閱讀 1,052評論 0 1
  • 為什么需要Vuex 通常 Vue 項目中的數(shù)據(jù)通信,我們通過以下三種方式就可以解決壹甥,但是隨著項目多層嵌套的組件增加...
    尤小小閱讀 1,071評論 1 5
  • 一救巷、前言 當我們的應用遇到多個組件共享狀態(tài)時,會需要多個組件依賴于同一狀態(tài)抑或是來自不同視圖的行為需要變更同一狀態(tài)...
    浪里行舟閱讀 1,531評論 0 8
  • Vuex 是什么? Vuex 是一個專為 Vue.js 應用程序開發(fā)的狀態(tài)管理模式它采用集中式存儲管理應用的所有組...
    coderlion閱讀 363評論 0 0
  • 前言 Vuex作為Vue官方維護和推薦的全局狀態(tài)管理插件句柠,是使用Vue框架的前端開發(fā)所必須掌握的一個知識點浦译,實際上...
    moutory閱讀 1,258評論 0 0