小白整理了VUEX

2023-08-27 06:00:30

在小白開發的專案中前端使用的是Vue,雖然在日常工作中可以使用Vue進行開發工作。但是沒有系統的學習過Vue,對Vue的一些特性和方法使用時常常需要查詢資料解決問題,查詢資料常常會佔用大量時間,尤其對Vuex的使用。雖然可以通過很多Vue框架中帶有的Vuex框架直接使用,但是用的越多,小白就會覺得越混亂、越不明白,只知其用不知其意。於是小白決定系統學習一下Vuex,來補充一下Vue知識。

1.Vuex是什麼?

Vuex是一個用於Vue.js應用程式的狀態管理模式。它可以集中管理Vue應用程式中的所有元件的狀態,並提供了一種機制來保持狀態的一致性和可追蹤性。

2.Vuex中有哪些物件?

一個Vuex模組中通常包含以下五個物件:namespaced、state、mutations、actions 和 getters。這些物件分別用於定義模組的名稱空間、狀態、變更操作、非同步操作和計算屬性。

除了這五個物件,還有一些其他可選的物件可以在模組中使用:

  1. modules:如果你的模組需要進一步細分為子模組,可以使用 modules 物件來組織和巢狀這些子模組。
  2. plugins:你可以使用 plugins 陣列來安裝Vuex外掛,這些外掛可以監聽活修改狀態的變化。
  3. actions的輔助物件:在 actions 中,你可以定義 rootrootStatecommitdispatch 等引數,來存取根模組的狀態和呼叫根模組的 mutationsactions
  4. mutations的輔助物件:在 mutations 中,你可以定義 rootState 引數,來存取根模組的狀態。
  plugins: [
    // ...
  ],

  actions: {
    someAction({ rootState, commit, dispatch }) {
      // ...
    },
  },

  mutations: {
    someMutation(state, { rootState }) {
      // ...
    },
  },

3.從定義層面使用Vuex

  1. 安裝Vuex:使用npm或yarn安裝Vuex。
  2. 建立一個state:在你的Vue應用程式中建立一個 store 資料夾,並在其中建立一個 store.js 檔案。
  3. 定義狀態(State):在 store.js 檔案中,定義一個包含需要共用的狀態的物件。
  4. 定義mutations:在 store.js 檔案中,定義一系列用於修改狀態的mutations函數。每個mutation函數接收一個state物件作為引數,並根據需要修改狀態。
  5. 定義actions:在 store.js 檔案中,定義一系列用於處理非同步操作的actions函數。每個action函數可以呼叫一個或多個mutations函數來修改狀態。
  6. 定義getters:在 store.js 檔案中,定義一系列用於獲取state物件的「getters普通物件形式」或用於獲取state的計算屬性「getters函數」,可以通過「getters」來定義state狀態的衍生值或計算屬性並獲取。getters不是必須的。
  7. 註冊store:在你的Vue應用程式的入口檔案(main.js)中,匯入 store.js 並使用Vue.use()方法註冊Vuex。
  8. 在元件中使用狀態:使用 this.$store.state 來存取狀態,使用 this.$store.commit() 來呼叫mutations,使用 this.$store.dispatch() 來呼叫actions。
  9. 範例如下:

 

store.js

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

Vue.use(Vuex);

export default new Vuex.Store({
    state: {
      count: 0
    },
    mutations: {
      increment(state) {
        state.count++;    
      },
      decrement(state) {
        state.count--;
      },
      incrementByParam(state, amount) {
        state.count += amount;
      },
      decrementByParam(state, amount) {
        state.count -= amount;
      }
    },
    actions: {
      increment(context) {
        context.commit('increment');
      },
      incrementAsync(context) {
        setTimeout(() => {
          context.commit('increment');
        }, 1000);
      },
      decrement(context) {
        context.commit('decrement');
      }
    },
    getters: {
      // 物件形式的getters,允許以屬性的方式存取計算後的值,而無需呼叫函數
      getCount: state => state.count,
      // 函數形式的getters,可以接受額外的引數,並根據傳入的引數進行計算返回結果
      getCountByParam: (state) => (num) => {
        return state.count + num;
      }
    }
})

 

main.js

 import store from "xxxxx/store";

new Vue({
  store,
  // ...其他Vue應用程式的設定...
}).$mount('#app');
元件中使用getters
computed: {
    //函數形式的 getters 呼叫
    addNum() {
        return this.$store.getters.getCountByParam(2);
    },
    //物件形式的 getters 呼叫
    getNum() {
        return this.$store.getters.getCount;
    }
    //getters不是必須的
    num() {
        return this.$store.state.count
    }
}
觸發Mutations、Actions
//在Vue元件中通過 commit 方法觸發Mutations來修改狀態
methods: {
    increment() {
      this.$store.commit('increment');
    },
    decrement() {
      this.$store.commit('decrement');
    },
    //帶引數的increment
    incrementByParam() {
      this.$store.commit('incrementByParam', 5);
    },
    incrementAsync() {
      this.$store.dispatch('incrementAsync');
    },
    incrementAction() {
      this.$store.dispatch('increment');
    }
}

4.專案中使用時,為了專案的擴充套件性,通常使用Vuex模組來分割和組織狀態,如果使用了模組分割需要注意模組名稱空間。下面是使用模組的初級範例,其中getters演示了名稱空間的使用。

初級:使用模組分割
**store.js:**

import Vue from 'vue';
import Vuex from 'vuex';
import userModule from './user';

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    user: userModule,
  },
});

**user.js:**

export default {
  namespaced: true,

  state: {
    username: '',
    email: '',
  },

  mutations: {
    setUsername(state, payload) {
      state.username = payload;
    },

    setEmail(state, payload) {
      state.email = payload;
    },
  },

  actions: {
    updateUser({ commit }, payload) {
      commit('setUsername', payload.username);
      commit('setEmail', payload.email);
    },
  },
  getters: {
    getUserName: state => state.username
  }
};

**元件中的使用範例:**

computed: {
  username() {
    return this.$store.state.user.username;
  },
  username2() {
    //如果使用了模組名稱空間,就需要採用this.$store.getters['module/getterName']的方式來存取getter函數;
    //如果沒有使用模組名稱空間,可以直接通過this.$store.getters.getterName存取getter函數
    return this.$store.getters['user/getUserName']
  }
},

methods: {
  updateUser() {
    this.$store.dispatch('user/updateUser', { username: 'John', email: '[email protected]' });
  },
},

5.真實的專案我們可能需要多個modules,並且每個modules中getters、mutations、actions 和 state 通常會變得非常大,所以它們也需要用單個檔案分割。

store.js
import Vue from "vue";
import Vuex from "vuex";
import loggerPlugin from './plugins/logger';

//以下五個檔案是當前目錄下state、getters、mutations、actions分割出來後的檔案
import state from "./state";
import getters from "./getters";
import mutations from "./mutations";
import actions from "./actions";

Vue.use(Vuex);

const myPlugin = store => {
  store.subscribe((mutation, state) => {
    // 在這裡可以監聽 mutation 的變化和存取 state
  });
};

//下面是將整個模組分割出來
import moduleCard from "xxx/cart/moduleCart.js"
import module2 from "xxx/xxx/module2.js"
import { module3 } from "已安裝元件"

export default new Vuex.Store({
  namespaced: true,
  state,
  getters,
  mutations,
  actions,
  plugins: [loggerPlugin, myPlugin],
  modules: {
    cart: moduleCart,
    moduleName2: module2,
    //這個程式碼片段中的 ...module3 是使用 ES6 的擴充套件運運算元將 module3 模組中的內容解構到 modules 物件中。
    //這樣做可以方便地將 module3 模組的 state、mutations、getters 和 actions 新增到 Vuex 的模組集合中。
    ...module3,
  },
  //在 Vue.js 中,strict 是一個用於開啟嚴格模式的選項。當 strict 設定為 true 時,Vuex 的狀態變更會被嚴格監測,以便捕捉到狀態的不合規變更。
  //在你提供的程式碼中,process.env.NODE_ENV !== "production" 是一個條件判斷語句,它用於根據當前執行環境來確定是否開啟嚴格模式。通常,在開發環境中,我們會將 process.env.NODE_ENV 設定為 "development",而在生產環境中會設定為 "production"。
  //當 process.env.NODE_ENV !== "production" 為 true 時,說明當前不處於生產環境,此時 strict 會被設定為 true,即開啟嚴格模式。這樣做的目的是為了方便在開發階段捕捉到狀態變更的錯誤,以及進行更加詳細的狀態變更追蹤和錯誤提示。
  //一般來說,建議在開發環境中開啟嚴格模式,而在生產環境中關閉嚴格模式,以獲得更好的效能和體驗。這可以通過構建工具(如 webpack)來設定 process.env.NODE_ENV 的值來實現。
  strict: process.env.NODE_ENV !== "production",
});

下面用moduleCart作為範例來演示一個Vuex模組中五個物件的分割: namespaced,state,mutations,actions 和 getters。建立一個資料夾名為cart,在資料夾中建立五個檔案分別為moduleCart.js、moduleCartActions.js、moduleCartGetters.js、moduleCartMutations.js和moduleCartState.js

moduleCart.js
 import state from "./moduleCartState.js";
import mutations from "./moduleCartMutations.js";
import actions from "./moduleCartActions.js";
import getters from "./moduleCartGetters.js";

export default {
  namespaced: true,
  state: state,
  mutations: mutations,
  actions: actions,
  getters: getters,
};
moduleCartActions.js
在actions中可以使用store,以使用已存狀態資料
import store from "../store.js";

export const addToCart = ({ commit }, product) => {
  commit('addProduct', product);
};

export const removeFromCart = ({ commit }, productId) => {
  commit('removeProduct', productId);
};

//或者下面方式
export default {
    addToCart({ commit }, product) {
        commit('addProduct', product);
    },
    removeFromCart({ commit }, product) {
        commit('removeProduct', productId);
    },
    //包含輔助物件的action,使用`rootState`來存取根模組的狀態,使用`state`來存取當前模組的狀態
    addToCart2({ commit, rootState, state }) {
      commit('addProduct', product);
      console.log(rootState); // 存取根模組的狀態
      console.log(state); // 存取模組的狀態
    },
     removeFromCart2({ commit, rootState }) {
      commit('removeProduct', productId);
      console.log(rootState); // 存取根模組的狀態
    },
}
moduleCartGetters.js
export const cartProducts = state => state.products;

export const totalItems = state => state.products.length;

或者

export default {
    cartProducts:state => state.products,
    totalItems: state => state.products.length,
    cartProducts2(state, getters, rootState, rootGetters) {
      console.log(rootState); // 存取根模組的狀態
      console.log(rootGetters); // 存取根模組的getters
      return state.products;
    },
};
moduleCartMutations.js
 export const addProduct = (state, product) => {
  state.products.push(product);
};

export const removeProduct = (state, productId) => {
  state.products = state.products.filter(p => p.id !== productId);
};

或者
import Vue from "vue";
export default {
    addProduct(state, product) {
        Vue.set(state, "products", product);
    },
    removeProduct(state, productId) {
        Vue.set(state, "products", state.products.filter(p => p.id !== productId))
    }
}
moduleCartState.js
 export default {
  products: [],
};
plugins
 **plugins/logger.js:**
const loggerPlugin = store => {
  store.subscribe((mutation, state) => {
    console.log('mutation type:', mutation.type);
    console.log('mutation payload:', mutation.payload);
    console.log('state:', state);
  });
};

export default loggerPlugin;

以上就是小白用心整理的Vuex的內容,通過整理小白對Vuex有了更多的瞭解,之前小白不理解不明白的地方明,現在明白了。小白會在編碼的路上繼續努力、繼續加油!