Vue.js - Vuex-新手上路-自 store 中取得與修改

適用:

  • 會基本的 Vue 應用(使用 data / computed / method / 插值... 等)


無 Vuex 時資料傳遞的作法

上傳下:props in
下傳上:emit out
同層級:event bus (簡單情境, 資料量不大時)
或是透過全域變數,但是全域變數無法雙向綁定
( 可參考 無 Vuex 的 Components 間的各種資料傳遞 )


Vuex 的運作原理與流程

Image

  1. component 中以 dispatch 方法去觸發 action 事件
  2. action 裡處理同步/異步(如 ajax / setTimeout..等)事件操作
    ( 需要打 API 來取得資料的話,也在此處理)
    並將資料 commitmutation
  3. mutation 去改變 State (資料)
  4. state 再回應到 component 裡進行 Render

Vuex 的組成

核心 - store 倉庫

  • component 從 store 中讀取資料狀態 (state)

1. state(data)

  • 響應式的資料狀態儲存, 資料狀態變化時,有用到的 component 都會即時更新

2. action(methods)

  • 操作同步或異步事件的處理但不直接修改資料(state)
  • 是透過commit → 呼叫 mutation 改變 state

3. getter(computed)

  • 加工資料呈現
  • 同 computed 一樣會被緩存、依賴值變更了才會重新計算

4. mutation

  • 改變state
  • 只處理同步函數:不要在這進行非同步的動作(例如 setTimeout / 打 API 取遠端資料...等)

以下以 CLI 環境為例

4-1.安裝

安裝

  1. 安裝 Vuex : npm install vuex --save / yarn add vuex

  2. 引入至專案 src/main.js

     ...
     import Vuex from 'vuex'
    
     Vue.use(Vuex)

4-2.應用-從 store 中取 state 資料

Step1. src下 新增檔案 store/index.js

  • src/ store / index.js

      import Vue from 'vue'
      import Vuex from 'vuex'
    
      Vue.use(Vuex)
    
      export default new Vuex.Store({
        state: {
          test: 'test data'
        }
      })
  • 修改 src/main.js

      import store from './store'
      ...
      ...
      new Vue({
        el: '#app',
        store,                // -> store: 'store'
          ...
      })
      ...

Step2. computed 內增加取得資料的方法

  • component - script 內以 this.$store.state.__ 取得 store 內的資料

      ...
      computed: {
          test () {
              return this.$store.state.test
          }
      }
      ...
  • component - template 引入

      {{test}}

4-3.應用-修改 store 中的 state 資料

方法1. 在 componet 中直接修改(最好不要這這麼做)

  • 例: <button @click = "___">Change</button>

      <...@click="changeHandler()'">
      ...
      changeHandler() {
          this.$store.state.test = 'balabala'
      }

      < ...@click="$store.dispatch('updateTest','balabala')">

方法2. Vuex: dispatch -> [action] -> commit -> [mutation]

  • Step1. stroe/index.js 增加 actionsmutations 物件

      ...
      export default new Vuex.Store({
          state: {
              ...
          },
          actions: {
          
          },
          mutations: {
          
          },
      })
  • Step2. 定義 actionsmutation

    • action 裡將接收到的資料 commit 至 mutation
    • mutation 內將 action commit 進來的資料傳給 state (修改 state)

      ...
        actions: {
            updateTest(context, status) {
                context.commit('TEST', status)     // mutation 中定義方法
            }
        },
        mutations: {
            TEST(state, status) {      //status -> payload (載荷)
                state.test = status;
            }
        },
      ...
    • 關於 Action | 關於 Mutation

  • Step3. component 中修改資料的方式改寫用dispatch

    dispatch 觸發 action 事件, 並傳遞內容

      <...@click="changeHandler()'">
      ...
      changeHandler() {
          this.$store.dispatch('updateTest','balabala')
      }
      < ...@click="$store.dispatch('updateTest','balabala')">

差異

  • 應避免使用方法1, (從 DevTool Vue 工具裡的 Vuex 裡觀察,方法 1 並沒有修改到 store state)

4-4.應用-getters :資料加工

  • Step1. getters 中新增一個方法與回傳值(同 computed 用法)

      ...
      export default new Vuex.Store({
        state: {
          text: '...'
        },
          actions: {
              ...
          },
          mutations: {
              ....
          },
          getters: {
              textLength: state => {
                  return state.test.length
              }
        }
      })
  • Step2.component中 $store.getters.___ 可直接取得資料

      {{$store.getters.textLength}}

練習簡單的例子:

  1. 先載入預設的名字
  2. 計數名字字數
  3. 使用者輸入新名字按下 Enter 後修改名字。
  4. 計數名字字數也應及時更新

Demo

> CodeSandbox

(點左上角選單按鈕可以展開目錄欄,瀏覽檔案)


DevTool-Vue 中的 Vuex 面板

Image

有透過 action 跟 mutation 操作,會多了 mutation 欄位, 且 也能紀錄變化歷程

Image


開啟 Vuex 嚴謹模式

  • stroe/index.js 開啟嚴謹模式:strict: true

      export default new Vuex.Store({
          strict: true,
          state: {
              ...
          },
          ...
      })

    嚴謹模式下,若你在 mutation 之外的地方直接改變 state 內容,會出現 error
    (在 component 內或 action內 寫都不行!)

參考資料