第12屆鐵人賽Day 23 Rails專案開發 - Vuex狀態管理 (1)

昨天我把一張自己開給自己的票:拖拉ticket解決了!

接著換下一張票、同時也就是今天的鐵人賽主題:改寫成Vuex來管理狀態~

在鐵人賽第13天的時候曾經聊到Vuex狀態管理,當我們的專案發展規模越來越大,元件越來越多,如何讓資料在跨元件之間溝通就是一件非常重要的事情。 (如果一直讓子元件用$emit傳給父元件、父元件再用props傳給其他子元件,這樣來來回回也太辛苦了吧~~~)

這時候,我們會使用Veux去產生一個用來管理網站全域的Shared State(共享狀態)的實體,而這個實體我們通常會把它取名叫做store(英文意思為倉庫)。

參考官網影片介紹的Vuex架構,今天我們就來把原本元件裡的data(如下圖左側)拉出來到store(下圖右側)獨立管理吧!

Step0. 安裝並引入Vuex

首先在Rails 6專案裡利用指令yarn add vuex安裝,這在第13天已經進行過了~

yarn add vuex 
//略
...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ vuex@3.5.1
info All dependencies
└─ vuex@3.5.1
✨  Done in 3.30s.

Step1. new出Vuex的實體

在今天的任務,要從Vue元件裡的data拉出來、挪到store獨立管理的State叫做columns,先跟之前的元件寫法一樣,預設是一個空陣列。

如果元件想要使用State的話,是使用Getters屬性取值(stateGetter的第一個參數)

參考官網教學影片的Store流程圖:

我們寫在stores/column.js的路徑下的Vuex元件長得像這樣:

import Vue from 'vue/dist/vue.esm'
import Vuex from 'vuex'

Vue.use(Vuex)

// 定義一個新的 Vue Store
export default new Vuex.Store({
  state: {
    // 預設空陣列
    columns: []
  },
  getters:{ 
    columns: state => state.columns
  },
  mutations: {
    // 任何更改columns的值的行為都必須透過mutation
    UPDATE_COLUMNS(state, columns){
      state.columns = columns;
    }
  },
  actons: {
  }
});

Step2. application.js 引入 Vuex的store

剛剛寫完熱騰騰的column.js趕快引入到原本的component:

import store from 'stores/column'

並且在new Vue裡面應該再加上store(import後就可以使用)

import Vue from "vue/dist/vue.esm";
import Column from "components/kanban/column"
import Rails from '@rails/ujs'
import Draggable from 'vuedraggable';
import store from 'stores/column';

document.addEventListener("turbolinks:load", () => {
  let el = document.querySelector("#column");
  if (el){
    new Vue({
      el,
      store, // import後就可以使用store
      data: {
        kanban_id: el.dataset.kanbanid,
        // columns: []   => 此時已經把column資料挪到Vuex裡了,原本的Vue可以把此段移除
      },
      components: { Column, Draggable },
      methods: {
       // 略
      },
      beforeMount(){
        // 略
      }
    });
  }
})

而Veux最大的重點是:之後有任何想要進行修改State的動作,都必須要透過Actions提交commit給Mutations。 (至於Actions在今天的需求裡該怎麼撰寫呢?稍安勿躁,請繼續往下看~)

Step3. 思考:Column的Actions

之前在講解column元件時,有帶到生命週期的beforeMount(),在這個lifecycle hook會在畫面渲染至瀏覽器前的階段,把打API的結果更新至column陣列。 所以你應該猜到了~我們接下來要把以下這段beforeMount改寫進Actions

beforeMount(){
  Rails.ajax({
    url: `/kanbans/${this.kanban_id}/columns.json`,
    type: 'GET',
    dataType: 'json',
    success: result => {
      this.columns = result;
    },
    error: error => {
      console.log(error);            
    }
  });
}

以上是Vuex作用的流程圖,為了透過Actions提交commit給Mutations

我們把上一段搬移進去Vuex.Store的columns.js,

寫一個名為fetchColumn()的function,參數有commit,以及打後端API路徑需要知道的kanbanid

  actions: {
    fetchColumn({ commit }, kanbanid){
      Rails.ajax({
        url: `/kanbans/${kanban_id}/columns.json`,
        ///API路徑:kanbans/2/columns.json

        type: 'GET',
        dataType: 'json',
        success: result => {
          commit("UPDATE_COLUMNS", result);
          //console.log(result);

        },
        error: error => {
          // console.log(error);            
        }
      });    
    }
  }

以下是專案的程式碼截圖: 左邊代表原本的Vue寫法,右邊是改寫為Vuex 主要把beforeMounted的code移動到actions來,再透過commitmutation把資料寫回去:

是不是跟Vuex官網的架構有87%像啊?(所以說~~官網要認真看!)

改寫完Vuex之後,點擊Kanban,可以順利載入Column以及所屬的ticket

於是我們又可以把這一張票:改寫成vuex管理狀態移到DONE了 :)

https://ithelp.ithome.com.tw/upload/images/20201005/20111177YYgjPkvnRa.png

小提醒:

  • javascript可以善用console log把接到的資料印出來看看,加快開發速率喔!
  • Vue devtool也要隨時開著,看有沒有紅字錯誤或警告訊息~

Ref: