jeremygo

jeremygo

我是把下一颗珍珠串在绳子上的人

Vuex 核心

在封裝 Hy-Vue-Admin 的登錄邏輯時,對於登錄狀態的管理設計剛開始利用很直觀的全局 cookie 保存狀態,寫起來感覺很別扭而且麻煩,參考了成熟的後台管理模板登錄的邏輯以後決定使用 Vue 官方推薦的 Vuex 進行全局狀態的管理:

Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。 —— 官方定義

使用原因#

  • 使用 Vue 開發單頁應用時,經常需要操作一些組件間共享的數據或狀態:
    • 應用規模較小時,可以使用 props、事件等常用的父子組件的組件間通信方法,單向數據流
    • 應用規模較大時,即多個組件共享狀態時,單向數據流的簡潔性很容易被破壞:
      • 多個視圖依賴於同一狀態
      • 不同視圖的行為需要變更同一狀態
  • 傳統解決方式存在的問題:
    • 對問題一:傳參的方法在多層嵌套的組件下將會變得十分繁瑣並且無法處理兄弟組件間狀態傳遞的情況
    • 對問題二:經常採用父子組件直接引用或者通過事件來變更和同步多個組件間狀態的多份拷貝,這種模式非常低效,很容易導致無法維護的代碼
  • 新的思路:
    • 將組件的共享狀態抽取出來,以一個全局單例模式管理
    • 不管在組件樹的哪個位置,任何組件都能直接獲取狀態或者觸發行為
    • 通過定義和隔離狀態管理中的各種概念並且強制遵守一定的規則,代碼會更結構化且易維護

先放一張官方圖~~

image

核心概念#

State#

單一狀態樹理念,每個應用只包含一個 store 實例

  • Vuex 通過 store 選項將狀態從根組件注入到每一個子組件中(Vue.use(Vuex)):

    const app = new Vue({
        el: '#app',
        store, // 把 store 對象提供給 store 選項
        components: { Counter }
    })
    
  • Vue 組件中獲取 Vuex 狀態:子組件通過 this.$store 訪問到 store 實例

    const Counter = {
        template: `<div>{{ Count }}</div>`,
        computed: {
            count () {
                return this.$store.state.count
            }
        }
    }
    
  • mapState 輔助函數 與 對象展開運算符

  • 組件仍然保有局部狀態

    • 使用 Vuex 並不是一定需要將所有的狀態放入 Vuex
    • 如果有的狀態嚴格屬於單個組件,最好還是作為組件的局部狀態

Mutation#

更改 Vuex 中的 store 中的狀態的唯一方法是提交 mutation:

  • 每個 mutation 都有一個字符串的 事件類型(type) 和一個 回調函數(handler)。回調函數就是我們實際進行狀態更改的地方,並且它會默認接受 state 作為第一個參數
const store = new Vuex.Store({
    state: {
        count: 1
    },
    mutations: {
        increment (state) {
            state.count++
        }
    }
})
  • 不能直接調用一個 mutation handler,要以事件註冊的理念:當觸發一個類型為 increment 的 mutation 時,調用此函數
store.commit('increment')
  • 提交載荷:可以向 store.commit 傳入額外的參數
  • Mutation 必須是同步函數:任何由 mutation 事件類型導致的狀態變更都應在此刻完成

Action#

類似於 mutation ,區別:

  • Action 提交的是 mutation,不是直接變更狀態
  • Action 可以包含任意異步操作
const store = new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {
        increment (state) {
            state.count++
        }
    },
    actions: {
        increment (context) {
            context.commit('increment')
        }
    }
})

Action 函數接受一個與 store 實例具有相同方法和屬性的 context 對象,即可以通過 context.commit 提交一個 mutation

  • Action 通過 store.dispatch 方法觸發:

    store.dispatch('increment')
    

Module#

使用單一狀態樹,應用的所有狀態將會集中到一個很大的對象,store 對象容易變得臃腫

因此,Vuex 允許我們將 store 分割成模塊,每個模塊擁有自己的 state、mutation、action 甚至是嵌套子模塊

解決方案#

src 目錄下寫全局狀態管理的代碼,其中包含了 user 的狀態

src
|—— api
  |—— login.js      # user login api接口
|—— ……
|—— ……
|—— store
  |—— modules
  	|—— user.js     # store中的user module
  |—— getters.js
  |—— index.js
|—— utils
  |—— auth.js       # 對user token的相關操作
  |—— request.js    # axios 登錄請求的攔截器

store 中的 user module:

image

Login.vue 中 點擊登錄分發 Action Login:

image

user 模塊中 actions 首先調用登錄接口,成功返回 token 後提交 commit 設置 state token 並且使用 cookie 保存 token:

image

至此登錄保存 token 狀態的整體邏輯完成

退出的邏輯也與這個類似,點擊退出分發 action,調用退出接口返回成功狀態碼後提交 commit 設置 state token 為空並刪除 cookie,可自行閱讀實現代碼~

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。