示例 透過 Vuex 讀取與修改 store 內的 state。

適用:

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

# 無 Vuex 時資料傳遞的作法

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


# 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;
    		}
    	},
    ...
    
  • 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內 寫都不行!)


# (參考資料)