Vuex (狀態管理模式)

概述

Vuex 是 Vue.js 官方提供的狀態管理模式(state management pattern)與函式庫,用來在 Vue 應用中集中管理多個元件共享的資料(state)。

當小型應用只有幾個元件時,父子元件之間用 props$emit 傳資料已經足夠。但當應用變大、元件變多,資料需跨元件甚至跨層級傳遞時,就會變得複雜又難以維護。

這時 Vuex 就能派上用場:

它提供一個「全域的資料儲存區(store)」,讓所有元件都能讀取與更新同一份資料。


核心概念

名稱 說明
state 存放資料的地方(類似資料庫)
getters 類似 computed,用來取得經過處理的 state
mutations 用來同步地修改 state 的方法
actions 用來處理非同步流程,然後呼叫 mutations
modules 當 store 太大時可拆成模組

安裝與設定

安裝

# Vuex 4 支援 Vue 3,Vuex 3 用於 Vue 2
npm install vuex@4

建立主 store:store/index.js

// resources/src/store/index.js
import { createStore } from 'vuex';

const store = createStore({
  state: {
    user: null,
  },
  mutations: {
    setUser(state, payload) {
      state.user = payload;
    },
  },
  actions: {
    fetchUser({ commit }) {
      // 模擬從 API 抓資料
      const user = { name: 'Jack', role: 'engineer' };
      commit('setUser', user);
    },
  },
  getters: {
    isLoggedIn: (state) => !!state.user,
  }
});

export default store;

app.js 註冊 store

import store from './store'; // 引入 Vuex store

createApp(App)
  .use(router)
  .use(store)  // 註冊 Vuex
  .mount('#app');

資料夾結構建議

store/
├── index.js        # 主 store
├── modules/
│   ├── articles.js # 文章模組
│   └── users.js    # 使用者模組

模組化範例

modules/articles.js

// store/modules/articles.js
export default {
  namespaced: true,
  state: () => ({
    list: [],
  }),
  mutations: {
    setArticles(state, articles) {
      state.list = articles;
    },
  },
  actions: {
    fetchArticles({ commit }) {
      // 模擬 API 呼叫
      const data = [
        { id: 1, title: 'Vue 3 教學' },
        { id: 2, title: 'Laravel 與 Vue 整合' }
      ];
      commit('setArticles', data);
    },
  },
  getters: {
    articleCount: (state) => state.list.length,
  }
};

modules/users.js

// store/modules/users.js
export default {
  namespaced: true,
  state: () => ({
    currentUser: null,
  }),
  mutations: {
    setUser(state, user) {
      state.currentUser = user;
    },
  },
  actions: {
    fetchUser({ commit }) {
      // 模擬 API
      const user = { id: 1, name: 'Jack' };
      commit('setUser', user);
    },
  },
  getters: {
    isLoggedIn: (state) => !!state.currentUser,
  }
};

store/index.js 匯入模組

// store/index.js
import { createStore } from 'vuex';
import articles from './modules/articles.js';
import users from './modules/users.js';

export default createStore({
  modules: {
    articles,
    users,
  }
});

元件中使用模組資料

<script setup>
import { useStore } from 'vuex';
import { onMounted, computed } from 'vue';

const store = useStore();

onMounted(() => {
  store.dispatch('articles/fetchArticles'); // 使用模組名稱 prefix
  store.dispatch('users/fetchUser');
});

const articles = computed(() => store.state.articles.list);
const user = computed(() => store.state.users.currentUser);
</script>

<template>
  <div>
    <h2>文章列表</h2>
    <ul>
      <li v-for="a in articles" :key="a.id">{{ a.title }}</li>
    </ul>

    <h2>登入使用者</h2>
    <p>{{ user?.name }}</p>
  </div>
</template>

使用順序與觀念整理

典型流程:

  1. 使用 store.dispatch('模組名稱/action') 呼叫 action(可處理非同步)
  2. action 中呼叫 commit('mutation') 修改資料
  3. 元件透過 store.statecomputed() 取得資料顯示畫面

呼叫時機:

  • onMounted():元件初始化時抓資料
  • watch():變數變化時觸發
  • 點擊事件:例如按下「重新整理」

搭配 async/await:

await store.dispatch('users/fetchUser');
console.log('會員資料已更新');

命名空間與使用方式說明

項目 說明
namespaced: true 為模組啟用命名空間,呼叫 action/mutation/getter 時需加上模組名
modules 將各模組匯入並註冊於主 store 中
使用方式 store.state.模組名.keystore.dispatch('模組名/method')store.getters['模組名/getter']

官方文件參考