使用 Vuex 集中管理 Vue.js 的狀態

什麼是 Vuex?

Vuex 是 Vue.js 的狀態管理庫,可以讓多個組件或頁面共享和管理狀態。使用 Vuex 讓狀態管理更加清晰和可維護,特別是在大型應用中,幫助開發者更容易地追蹤和維護應用的狀態。

Vuex 的主要特點

  1. 集中式存儲:所有的應用狀態都集中在一個 store 中,方便管理與維護。
  2. 單向數據流:組件之間的數據流動是單向的,避免了數據不一致的問題。
  3. 狀態記錄:可以利用 Vue Devtools 查看狀態的變化,讓工程師更快發現問題進行除錯。

Vuex 的核心概念

  1. State:資料的狀態,類似於 Vue 2 中的 data
  2. Getters:獲取 state 的資料狀態,類似於 Vue 2 中的 computed
  3. Mutations:同步修改 state 的方法,必須以同步函數的形式進行。
  4. Actions:處理非同步操作,通常用來觸發 mutations,相當於 Vue 2 中的 methods

Vuex 運作流程圖

The operating principles of Vuex

如何安裝 Vuex

如果你使用 Vue CLI 建立項目,通常可以在安裝時選擇安裝 Vuex。如果沒有的話可以使用 npm 安裝:

1
npm install vuex

如何使用 Vuex

建立 store 資料夾

首先,在專案中創建一個名為 store 的資料夾,並在裡面建立一個空的 index.js 文件。

Vuex project path

接下來,將以下程式碼複製並粘貼到 index.js 中:

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

Vue.use(Vuex);

export default new Vuex.Store({
strict: true, // 嚴謹模式
state: {
},
getters: {
},
mutations: { // 操作狀態,不能寫非同步行為 setTimeout、AJAX,後續會難以除錯
},
actions: { // 操作行為,不能改變資料狀態,非同步行為 setTimeout、AJAX 寫在這裡
},
getters: {
},
modules: {
},
});

關於 strict: true, // 嚴謹模式 有興趣可以參考這篇文章 Vuex 的嚴謹模式

關於 modules 模組化有興趣可以參考這篇文章 Vuex Modules 模組化提升 store 的維護性

在 Vue 中使用 Store

最後,在你的 main.js 中引入並使用這個 store:

1
2
3
4
5
6
7
8
import Vue from 'vue';
import App from './App.vue';
import store from './store';

new Vue({
render: h => h(App),
store
}).$mount('#app');

基本範例

以下是一個簡單的 Vue Store 範例,展示如何使用 Vuex 來管理一個計數器的狀態。

建立 Store

打開 store/index.js 建立計數器 Store

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
state: {
count: 0
},
getters: {
count: state => state.count
},
mutations: {
increment(state) {
state.count++;
},
decrement(state) {
state.count--;
}
},
actions: {
increment({ commit }) {
commit('increment');
},
decrement({ commit }) {
commit('decrement');
}
}
});

export default store;

創建組件

現在,我們來創建一個簡單的計數器組件 Counter.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<div>
<h1>計數器: {{ count }}</h1>
<button type="button" @click="increment">增加</button>
<button type="button" @click="decrement">減少</button>
</div>
</template>

<script>
export default {
name: 'CounterComponent',
computed: {
count() {
return this.$store.getters.count;
}
},
methods: {
increment() {
this.$store.dispatch('increment');
},
decrement() {
this.$store.dispatch('decrement');
}
}
};
</script>

將組件加入頁面

最後,到 App.vueCounter 組件引入並放入頁面中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div id="app">
<Counter />
</div>
</template>

<script>
import Counter from './Counter.vue';

export default {
components: {
Counter
}
};
</script>

完成畫面

Vuex example

使用 API 獲取資料並更新 Vuex Store

這一部分將介紹如何通過 API 獲取資料並將其存儲在 Vuex 中。

我們將使用 randomuser API 隨機獲取使用者資料。在這個範例中,我們會運用 mapActionsmapState 將程式碼從 store 中解構,以提升可讀性,並使組件與 Vuex store 之間的互動更加直觀。

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<template>
<div id="app">
<button type="button" @click="fetchData">Fetch Data</button>
<hr>
<div v-if="loading">Loading...</div>
<div v-if="data">
{{ data }}
<hr>
<div>
<img :src="data.picture" alt="User Picture">
</div>
<div>姓名:{{ data.name }}</div>
<div>電話:{{ data.phone }}</div>
</div>
</div>
</template>

<script>
import { mapActions, mapState } from 'vuex';

export default {
name: 'App',
computed: {
...mapState(['data', 'loading']),
},
created() {
this.fetchData();
},
methods: {
...mapActions(['fetchData']),
},
};
</script>

store.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios';

Vue.use(Vuex);

const store = new Vuex.Store({
state: {
data: null,
loading: false,
},
mutations: {
SET_DATA(state, payload) {
state.data = payload;
},
SET_LOADING(state, payload) {
state.loading = payload;
},
},
actions: {
async fetchData({ commit }) {
commit('SET_DATA', null);
commit('SET_LOADING', true);
try {
const response = await axios.get('https://randomuser.me/api/');
const data = response.data.results[0];

// 提取所需資料
const userData = {
name: `${data.name.first} ${data.name.last}`,
phone: data.phone,
picture: data.picture.large,
};

commit('SET_DATA', userData);
} catch (error) {
console.error(error);
} finally {
commit('SET_LOADING', false);
}
},
},
});

export default store;

完成畫面

Vuex randomuser example

總結

Vuex 提供了一種集中管理應用狀態的方式,使得組件之間的狀態共享和管理變得更加簡單。透過 state、mutations、actions 和 getters,我們可以輕鬆地處理複雜的狀態邏輯。

這篇筆記只是 Vuex 的基本入門,更多用法如模組化和插件可以參考 Vuex 官方文檔。希望這能幫助你更好地理解和使用 Vue Store!