Vue-(十六)狀態管理 vuex(1/2)

關於 vuex

Vue的組件溝通

在單純的情況之下,兩個上、下層Vue組件若要進行溝通,會使用:

  • 由上傳下:上層使用 v-bind ,下層用props接到v-bind傳來的屬性資料
  • 由下傳上:下層發出$emit事件,上層則用v-on偵聽該事件

    eventbus

    若專案更大一些,資料不太可能$emit一層一層慢慢傳上去,上層組件用v-on偵聽到事件並拿到資料之後,又再一層層用props慢慢傳到另一個下層組件,這樣很麻煩也很難維護,所以這種結構複雜的跨組件溝通會使用 eventbus 來傳遞資料。

eventbus 的做法是另外創立一個 Vue 實例,假設要由 A 組件傳資料到 B組件,則在 A 組件中引入 eventbus ,A 組件請求 Vue實例透過 $emit 將資料傳進eventbus,而另一方面,B組件也引入 eventbus ,再透過 $on 偵聽 eventbus 發出的事件。

然而,eventbus 依然是有限制的,例:

當「購買按鈕」被按下之後,在「購物車」中要增添一筆資料,這個情況之下,資料不應該儲存在「購買按鈕」上,也不該儲存在「購物車」中,而是應當要儲存在一個統一管理的狀態裡面,因此就需要用到 Vuex 來做狀態管理。

Vuex

Vuex 大致上是透過一個 Global state 來儲存整個網站共有的狀態,而其設計概念是由「購買按鈕」組件 commit 一個 Mutation,而這個 Mutation 會改變 State,當 State 被改變時,則會觸發有使用到 State 的「購物車」組件的視覺元件被更新,而這整個觸法的過程是「單向運作」的。

Vuex 跟 eventbus 最主要的差異在於,Vuex 的 Global state 是組件共用的狀態,而非單純儲存在某個組件內部中的狀態。

所以本質上,組件與組件之間並沒有溝通,而是透過更新 Global State的狀態,而反應畫面到另外一個組件上。

使用 Vuex 時機

  • 組件之間很上互相溝通:不用Vuex
  • 組件僅需上下傳遞就很夠用:不用Vuex
  • 組件會互相溝通,但情境很固定,次數也很少:Event Bus
  • 組件之間會跨結構傳遞狀態:Vuex
  • 需要全域狀態管理:Vuex

引入 Vuex

step 1.先以指令安裝Vuex

1
2
3
4
5
//使用npm指令
npm i -S vuex

// or 使用yarn指令
yarn add vuex

step 2.在使用 webpack 打包的專案中,於 src 資料夾中新增一個檔案 store.js

step 3.開始在檔案中創建 store 實例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Vue from 'vue';//引入vue
import Vuex,{Store} from 'vuex';//引入vuex

Vue.use(Vuex);//註冊外掛Vuex,之後才能被使用

const store = new Store({//透過呼叫Store的建構函式,創建store實例
state:{
count:0,
},
mutations:{
addCount(state){
state.count +=1;
}
}
})

export default store;

另外一種寫法,也可以不引入{Store},而使用Vuex.Store 取得之

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);//

const store = new Vuex.Store({//使用Vuex.Store 取得之
state:{
count:0,
},
mutations:{
addCount(state){
state.count +=1;
}
}
})

export default store;

step 4.在整個專案的中使用該定義好的 store實例

第3行,在既有的專案中的 main.js引入 store.js;第5行,讓 store 成為整個專案 Vue實例中的一個屬性

1
2
3
4
5
6
7
8
9
10
11
import Vue from 'vue';
import App from './app.vue';
import store from './store.js';//use Vuex
new Vue({
store,//加入 store 屬性,讓所有的紫組件都可以使用
el: '#app',
data: {
message: '',
},
render: (h) => h(app),
});

step 5.在 app.vue中就可以直接以 this.$store 獲取並使用store

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div>
<h1>{{count}}</h1>
<button @click="addCount">Add</button>
</div>
</template>

<script>
export default {
computed: {
count() {
return this.$store.state.count;//獲取 store 的資料
}
},
methods: {
addCount() {
this.$store.commit("addCount");//commit mutation 到 store 中去更新資料
}
}
};
</script>

或是使用 Vuex 的工具函式 mapStatemapMutations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div>
<h1>{{count}}</h1>
<button @click="addCount">Add</button>
</div>
</template>

<script>
import { mapState , mapMutations} from 'vuex';//引入 mapState 和 mapMutations
export default {
computed:mapState(['count']),
methods:mapMutations(['addCount']),
};
</script>

又或者改寫搭配 ES6 的物件 spread(…) 語法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div>
<h1>{{count}}</h1>
<button @click="addCount">Add</button>
</div>
</template>

<script>
import { mapState , mapMutations} from 'vuex';//引入 mapState 和 mapMutations
export default {
computed:{
...mapState(['count']),
},
methods:{
...mapMutations(['addCount']),
}
};
</script>

step 6.開始執行,就可以看到畫面中的計數器

© 2020 Leah's Blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero