iT邦幫忙

2025 iThome 鐵人賽

DAY 19
2

在以dispatch呼叫actiion後,進而發送API請求,詳細的流程,要進一步查看Vuex的模組物件(module object),可以查看src/store/employee.module.js,參考如下。

// src/store/employee.module.js
import Vue from "vue";
import { EmployeeService } from "@/common/api.service";
import { FETCH_EMPLOYEES } from "@/store/actions.type";
import {

  SET_EMPLOYEES,
  SET_EMPLOYEE_COUNT,
  SET_NEXT_URL,
  SET_PREV_URL,
  SET_CURRENT_PAGE,
  SET_LOADING,
  
} from "@/store/mutations.type";

// 呼叫actions
export const actions = {

  async [FETCH_EMPLOYEES](context, params) {
    context.commit(SET_LOADING, true); // 可用來控制畫面的載入動畫(開始)
    try {
      const { data } = await EmployeeService.query(params); // 呼叫API拿資料
      context.commit(SET_EMPLOYEES, data.results); // 儲存資料列表
      context.commit(SET_EMPLOYEE_COUNT, data.count); // 儲存總筆數
      context.commit(SET_NEXT_URL, data.next); // 儲存下一頁的URL
      context.commit(SET_PREV_URL, data.previous); // 儲存上一頁的URL
      context.commit(SET_CURRENT_PAGE, params.page); // 更新目前頁碼
    } catch (err) {
      console.error("Failed fetching employees", err);
    } finally {
      context.commit(SET_LOADING, false); // 可用來控制畫面的載入動畫(結束)
    }
  },

};

// 對應的mutations
export const mutations = {

  [SET_EMPLOYEES](state, payload) {
    state.results = Array.isArray(payload) ? payload : [];
  },
  [SET_EMPLOYEE_COUNT](state, count) {
    state.count = count;
  },
  [SET_NEXT_URL](state, url) {
    state.next = url;
  },
  [SET_PREV_URL](state, url) {
    state.previous = url;
  },
  [SET_CURRENT_PAGE](state, page) {
    state.currentPage = page;
  },
  [SET_LOADING](state, flag) {
    state.isLoading = flag;
  },

};

// 對應的getters
export const getters = {

  employees: (state) => state.results,
  employeesCount: (state) => state.count,

  pageSize: (state) => state.pageSize,
  currentPage: (state) => state.currentPage,
  totalPages: (state) => Math.ceil(state.results.length / state.pageSize) || 1,

  nextPageUrl: (state) => state.next,
  prevPageUrl: (state) => state.previous,

  isLoading: (state) => state.isLoading,

};

export default {
  namespaced: true,
  state,
  actions,
  mutations,
  getters
};

在這段Vuex模組程式碼中,大致可區分為呼叫actions(非同步)、commit mutations(同步)及state/getters驅動畫面。

  • 在呼叫actions中,乃進行非同步操作,也就是先丟給API處理,等待其回傳值的過程中,畫面不會被定住。

  • 更精確地說,dispatch()所觸發的action,內部用await走非同步I/O,不會阻塞UI的執行緒;同時因為使用SET_LOADING控制載入動畫,可確保使用者有回饋。

  • 並且data乃是藉由EmployeeService.query(params)向API請求來取得。

  • 取得資料後,藉由一連串的commit來觸發對應的mutation函式,如SET_EMPLOYEES、SET_EMPLOYEE_COUNT、SET_NEXT_URL等,由mutation同步地改變state。值得注意的是,mutation是同步函式,負責直接修改state。

    // 呼叫actions
    export const actions = {
    
      async [FETCH_EMPLOYEES](context, params) {
        context.commit(SET_LOADING, true); // 可用來控制畫面的載入動畫(開始)
        try {
          const { data } = await EmployeeService.query(params); // 呼叫API拿資料
          context.commit(SET_EMPLOYEES, data.results); // 儲存資料列表
          context.commit(SET_EMPLOYEE_COUNT, data.count); // 儲存總筆數
          context.commit(SET_NEXT_URL, data.next); // 儲存下一頁的URL
          context.commit(SET_PREV_URL, data.previous); // 儲存上一頁的URL
          context.commit(SET_CURRENT_PAGE, params.page); // 更新目前頁碼
        } catch (err) {
          console.error("Failed fetching employees", err);
        } finally {
          context.commit(SET_LOADING, false); // 可用來控制畫面的載入動畫(結束)
        }
      },
    
    };
    
  • 接著,定義多個與employee模組對應的mutation,每個mutation都對應一個特定的狀態更新動作

    // 對應的mutations
    export const mutations = {
    
      [SET_EMPLOYEES](state, payload) {
        state.results = Array.isArray(payload) ? payload : [];
      },
      [SET_EMPLOYEE_COUNT](state, count) {
        state.count = count;
      },
      [SET_NEXT_URL](state, url) {
        state.next = url;
      },
      [SET_PREV_URL](state, url) {
        state.previous = url;
      },
      [SET_CURRENT_PAGE](state, page) {
        state.currentPage = page;
      },
      [SET_LOADING](state, flag) {
        state.isLoading = flag;
      },
    
    };
    
  • 而當state被mutation改變時,getters,如employees, employeesCount, totalPages等,會根據最新state重新計算,提供給組件(component),經由mapGetters('employee', [...])綁定後,畫面便自動響應更新。

    // 對應的getters
    export const getters = {
    
      employees: (state) => state.results,
      employeesCount: (state) => state.count,
    
      pageSize: (state) => state.pageSize,
      currentPage: (state) => state.currentPage,
      totalPages: (state) => Math.ceil(state.results.length / state.pageSize) || 1,
    
      nextPageUrl: (state) => state.next,
      prevPageUrl: (state) => state.previous,
    
      isLoading: (state) => state.isLoading,
    
    };
    
  • 到此,我們應該更能完全認識到Vuex的整體資料流,再次不厭其煩地說明,以為資料流的介紹做一個總結。

    Vue組件 → dispatch呼叫action(非同步) → action內部發送API請求 → commit多個mutation(同步) → mutation改變state → getters根據最新state重新計算 → 綁定在組件的畫面自動響應更新


上一篇
Day 18: Vue資料流與狀態管理-Vuex資料流及集中狀態管理
下一篇
Day 20: Vue字串管理及命名空間(namespaced)
系列文
從零打造網頁系統:非資訊人也能完成的全端專題實作20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言