iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 29
0
Modern Web

忍住不打牌位,只要30天VueJS帶你上A牌系列 第 29

Day29 Vuex狀態管理

前言

Vuex是甚麼?甚麼時候需要它?
其實我曾經教過大家父子元件的溝通可以透過props、emit,那如果不是父子關係的元件怎麼溝通?還不是太複雜的專案,其實是可以透過Event Bus 發起全域的事件送出事件或資料,元件可以用on來監聽Event Bus發出的事件或資料。

那當然如果專案結構比較複雜,就可以適用Vuex來做整個網站的全域狀態管理,將狀態集中在Store管理。

https://ithelp.ithome.com.tw/upload/images/20200929/20129187Ap5BqtPFSD.png

整個Vuex我們稱它為Store,工作流程如右圖示:

https://ithelp.ithome.com.tw/upload/images/20200922/20129187z4quwFXkTC.png

整體工作流程是:在Component需要更動狀態時使用dispath來觸發Action發出Commit去呼叫定義好的Mutations修改State,當狀態被改變時,會觸發Render渲染元件。我們可以透過Vue.js devtools來觀察其變化

Action

顧名思義,它的作用在於定義應用程式的行為,主要用在非同步的行為,如: call API。也就是說只能透過Action處理非同步,不能使用Mutation來處理。

Action 透過 Commit 向 Mutations告知使用哪個 mutation

Mutations

接收到Action發起的訊息,或單使用Commit呼叫mutation,執行其邏輯運算,來改變state狀態,也就是說只能由Mutation來修改狀態。

在強調一次:Action、Mutations實質相似,都可以處理業務邏輯,但在主要工作上有區分Action就是處理非同步,Mutations 就是負責改變狀態。

State

Vuex是管理狀態的機制,當然State及是負責記錄應用程式所有的狀態。

Module

當我們的狀態全部集中到同一個State就會變得臃腫複雜,所以Vuex提供了分割模組,讓每個模組有屬於自己的state、mutation、action、getter。

// define moduleA、moduleB here
...
// define Vuex
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA State
store.state.b // -> moduleB State

Getter

一言以蔽之,你可以把它認為是 store 的計算屬性。
就跟計算屬性一樣,getter 的返回值會根據它的依賴被cache起來,且只有當它的依賴值發生了改變才會被重新計算。
Getter 接受 state 作為其第一個參數,也可以接受其他getter 作為第二個參數。

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    },
    doneTodosCount: (state, getters) => {
      return getters.doneTodos.length
    }
  }
})

使用Vuex步驟:

1.定義Vuex
state要先定義該狀態isLoading,mutations在接受到commit才能發出變異mutate觸使狀態state改變。很重要在說一次,state要先定義狀態。

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    // 定義狀態
    isLoading: false,
  },
  mutations: {
    // 這邊寫好每次變異都把布林值轉換
    changeLoadingState (state) {
      state.isLoading = !state.isLoading
    }
  },
  actions: {
  },
  modules: {
  }
})

2.import到根實例

import Vue from 'vue'
import App from './App.vue'
import store from './store'

new Vue({
  store,
  render: h => h(App)
}).$mount('#app')

3.在component使用

<template>
  <div>
    <span v-if="isLoading"><i class="pi pi-refresh pi-spin"></i></span>
    <button @click="onChangeState()">Reverse</button>
  </div>
</template>
<script>
export default {
  name: "app",
  computed: {
    isloading() {
      // 透過$store取得狀態裡的isLoading
      return this.$store.state.isLoading;
    }
  },
  methods: {
    onChangeState() {
      // 透過$store commit 已經寫好的mutation
      this.$store.commit("changeLoadingState");
    }
  }
};
</script>

有任何問題歡迎下方留言,如果喜歡我的文章別忘了按讚、訂閱追蹤加分享唷!!
---我是分隔線-----------------------------------------------------------
PollyPO技術-前端設計轉前端工程師-JS踩坑雜記 30 天
喬依司-實作經典 JavaScript 30
五百億-Vue CLI + Firebase 雲端資料庫 30天打造簡易部落格及後臺管理
eien_zheng-前端小嘍嘍的Golang學習旅程_The journey of learning Golang


上一篇
Day28 使用Vue i18n創立一個多語系的網站
下一篇
Day30 完賽感想
系列文
忍住不打牌位,只要30天VueJS帶你上A牌30

尚未有邦友留言

立即登入留言