[ Nuxt.js 2.x 系列文章 ] VueX Store 搭配 vuex-persistedstate 狀態保存工具


版本:nuxt 2.15.8

前情提要一下,在 Vue 的專案下,常會需要做父子元件或是頁面之間的溝通傳值,如果說只是單層(ex:父元件 → 子元件、子元件 → 父元件、頁面 → 頁面),我們可以很簡單的使用 propsemitevent bus 即可,但在大型專案,共用資料就不是如此單純,可能會有元件內含元件、多層級的溝通,如果只用上述方法,對於開發及除錯都不便利,如下圖範例,元件 1-1元件 2-1 的溝通相對複雜。

為了處理高難度溝通,VueX 狀態管理工具就誕生了,那麼在 Nuxt 專案下又該怎麼使用呢?

首先先安裝 VueX 套件 npm i vuex@3.6.2

💡 Nuxt v2.x 必須搭配 VueX v3.x

接著在專案最外層新增 store 資料夾,並在裡面建立 .js 檔,範例使用 userInfo.js

export const state = () => {};
export const getters = {};
export const mutations = {};
export const actions = {};

Nuxt 專案會自動創建實例 new Vuex.Store(),將 store 檔案包裝進模組內,像這樣:

new Vuex.Store({
    modules: {
        userInfo: {
            namespaced: true,
            state: () => {},
            getters: {},
            mutations: {},
            actions: {}
        }
    }
});

VueX 基本架構:

  • state:用以儲存狀態,功能同 .vue 檔內的 data,因此會使用方法來包裝,並 return 內容
  • getters:功能同 computed,用以計算 state 內的狀態,不能直接改變 state
  • mutations:用來更改 state,不能使用非同步語法
  • actions:非同步語法只能寫在 actions,不能直接改變 state,需透過 mutations 改變 state

接著來替 store 加入一些內容吧

export const state = () => ({
    count: 0,
    products: [
        {
            name: 'food',
            onSale: false
        },
        {
      name: 'drink',
            onSale: true
        }
    ]
});
export const getters = {
    onSaleProducts(state) {
        return state.products.filter(item => item.onSale);
    }
};
export const mutations = {
    increment(state, number) {
    state.count += number;
  }
};
export const actions = {
    incrementAsync({ commit }, number) {
    setTimeout(() => {
      commit('increment', number);
    }, 1000);
  }
};

如果要在頁面使用 store 的內容,有以下兩種方式:

透過 this.$store 操作

VueX 將 store 注入到 Vue 實例,因此我們透過 $store 就可以取得相關資料及方法,

使用方式如下(範例頁面 pages/about.vue):

export default {
    name: 'About',
  computed: {
        count() { // state
            return this.$store.state.userInfo.count;
        }
        onSaleProducts() { // getters
            return this.$store.getters['userInfo/onSaleProducts'];
        }
    },
    methods: {
        increment(number) { // mutations
            this.$store.commit('userInfo/increment', number);
        },
        incrementAsync(number) { // actions
            this.$store.dispatch('userInfo/incrementAsync', number);
        }
    }
}

但是每一筆資料或是方法,都透過 this.$store 取得,程式碼冗長,如果今天我們有三個 store 儲存庫,易讀性又更低了,難道沒有簡單的使用方式嗎?

透過輔助函式

VueX 提供一系列輔助函式(mapState, mapGetters, mapMutations, mapActions),可以幫助我們更簡易的取得 store 內容,首先必須從 VueX 引入輔助函式,接著來改寫 about.vue 頁面

import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';

export default {
    name: 'About',
  computed: {
        ...mapState('userInfo', [ 'count' ]),
        ...mapGetters('userInfo', [ 'onSaleProducts' ])
    },
    methods: {
        ...mapMutations('userInfo', [ 'increment' ]),
        ...mapActions('userInfo', [ 'incrementAsync' ])
    }
}

透過輔助函式,減少許多程式碼,閱讀起來也輕鬆許多。


VueX 相當方便,但還是存在一個問題,就是當頁面重新整理的時候,會回復到初始狀態。

某些情境下,我們需要保留更新後的資料,例如登入後儲存使用者資訊到 store,重整頁面後資料被清空,使用者必須重新登入。為了解決這個問題,我們可以將資料儲存於 localStorage,待畫面重整後再將資料取回放入 store,或者是使用套件 vuex-persistedstate

💡 2022.02.04 vuex-persistedstate **套件已不繼續維護更新

接下來說明如何 Nuxt 專案如何搭配 vuex-persistedstate,存放在 localStorage 的內容,可以輕易地被讀取,因此我們需要將內容加密(搭配套件 secure-ls

首先安裝套件:npm i vuex-persistedstate

接著安裝加密套件:npm i secure-ls

於 plugins 增加檔案,範例使用 persistedstate.js

import createPersistedState from 'vuex-persistedstate';
import SecureLS from 'secure-ls';

const ls = new SecureLS({
    encodingType: 'aes', // 加密方式,預設 base64
    isCompression: false, // 是否壓縮數據
    encryptionSecret: process.env.APP_KEY // 加密 key
});

export default ({ store, isHMR }) => {
    if (isHMR) { // 避免在熱更新的時候重複觸發(npm run dev)
        return;
    }
    window.onNuxtReady(() => {
        createPersistedState({
            key: 'test', // 自訂 localStorage key
            storage: {
                getItem: key => ls.get(key),
                setItem: (key, value) => ls.set(key, value),
                removeItem: key => ls.remove(key)
            }
        })(store);
    });
};

接著配置到 nuxt.config.js 內

export default {
    plugins: [
        { src: '@/plugins/persistedstate', ssr: false }
    ]
}

這樣一來即使畫面重整,store 也可以順利保存資料,在 localStorage 查看 test 內容也確實被加密了!


參考文章:

https://medium.com/itsems-frontend/vue-vuex1-state-mutations-364163b3acac

https://chiafangsung.medium.com/使用-vuex-persistedstate-維持-vuex-狀態-f0d7c522c73a

#Nuxt #nuxt.js #Vue #Vue.js #ssr #vuex #store







你可能感興趣的文章

Day3 讓我見識一下吧,終端機的性能

Day3 讓我見識一下吧,終端機的性能

[4] 測試是一門學問,關於執行測試

[4] 測試是一門學問,關於執行測試

Python Table Manners - Commitizen: 規格化 commit message

Python Table Manners - Commitizen: 規格化 commit message






留言討論