iT邦幫忙

2021 iThome 鐵人賽

DAY 6
4
Modern Web

[ 重構倒數30天,你的網站不Vue白不Vue ] 系列 第 6

[重構倒數第25天] - Vuex + Composition API 組合技

  • 分享至 

  • xImage
  •  

前言

該系列是為了讓看過Vue官方文件或學過Vue但是卻不知道怎麼下手去重構現在有的網站而去規畫的系列文章,在這邊整理了許多我自己使用Vue重構很多網站的經驗分享給讀者們。

今天讓我們來聊聊如果使用 Vuex,要如何搭配 composition api 來幫助我們管理重複的邏輯以及抓取 Vuex 資料。

Mike Vue

我們先來看看這次的範例要做什麼

mike vue

這是一個非常簡單的網頁,有一個會滑入的選單以及滑入的 login 頁面,我們看一下專案結構。

|-- src
    |-- App.vue
    |-- main.js
    |-- assets
    |   |-- bg.jpg
    |   |-- close.svg
    |   |-- logo.png
    |-- components
    |   |-- Header.vue
    |   |-- Login.vue
    |   |-- SlidMenu.vue
    |-- store
    |   |-- index.js
    |-- view
        |-- Home.vue

首先是我們的 Vuex 的 store

import { createStore } from "vuex";

export default createStore({
  state: {
    loginState: false,
    menuState: false,
  },
  actions: {
    handleLoginState({ commit }, bool) {
      commit("SET_LOGIN_STATE", bool);
    },
    handleMenuState({ commit }, bool) {
      commit("SET_MENU_STATE", bool);
    },
  },
  mutations: {
    SET_LOGIN_STATE(state, bool) {
      state.loginState = bool;
    },
    SET_MENU_STATE(state, bool) {
      state.menuState = bool;
    },
  },
  getters: {
    loginState: (state) => state.loginState,
    menuState: (state) => state.menuState,
  },
});

在這邊我們會需要兩個狀態,一個控制 Menu、一個控制 login 的開關,然後設定相對應的 acions 以及mutations,取資料我使用 getters。

接下來看一下Header.vue的內容( CSS的部分我就不秀出來了)

Header.vue

<script>
import { computed } from "vue";
import { useStore } from "vuex";
export default {
  setup() {
    const store = useStore();
    const MenuState = computed(() => store.getters.menuState);
    const LoginState = computed(() => store.getters.loginState);
    const handleMenu = () => {
      store.dispatch("handleMenuState", !MenuState.value);
    };
    const handleLogin = () => {
      store.dispatch("handleLoginState", !LoginState.value);
    };
    return {
      headleMenu,
      headleLogin,
    };
  },
};
</script>

<template>
  <header>
    <nav>
      <a @click="handleMenu">Menu</a>
      <a @click="handleLogin">Login</a>
    </nav>
  </header>
</template>

這邊我定義了兩個 function 去對 store dispatch,然後取出 Menu 跟 login 的狀態,去做判斷,然後塞入dispatch中,綁定@click在兩個上,接下來看一下Menu跟Login的部分。

SlidMenu.vue

<script>
import { computed } from "vue";
import { useStore } from "vuex";
export default {
  setup() {
    const store = useStore();
    const MenuState = computed(() => store.getters.menuState);
    const CloseMenu = () => {
      store.dispatch("handleMenuState", false);
    };
    return { MenuState, CloseMenu };
  },
};
</script>
<template>
  <div :class="['slid_menu', { active: MenuState }]">
    <a class="close" @click="CloseMenu">
       <img src="../assets/close.svg" />
    </a>
    <nav>
      <a>ABOTU</a>
      <a>ADDRESS</a>
      <a>USER</a>
      <a>STRENGTH</a>
       <!-- 以下省略 -->
    </nav>
  </div>
</template>

Login.vue

<script>
import { computed } from "vue";
import { useStore } from "vuex";
export default {
  setup() {
    const store = useStore();
    const LoginState = computed(() => store.getters.loginState);

    return { LoginState };
  },
};
</script>
<template>
  <div :class="['login', { active: LoginState }]">
    <h1>Login Page</h1>
  </div>
</template>

我再Menu跟Login身上綁定了一個active的class,如果這個class被add上去了,就會把Menu給滑出來,如果remove掉了,就會收回去,然後Menu加一個function是可以把選單給關閉的。

以上的用法就是一個很典型的Vuex的使用方式,但是你會發現不管是在取得資料,以及操作dispatch的時候,感覺好像可以封裝一下,不用寫這麼多重複的code,這時候composition api 就派上用場啦!!!

我們先新增一個composition-api的資料夾,然後新增一個 useStateHandle.js

useStateHandle.js

import { computed } from "vue";
import { useStore } from "vuex";

export function useStateHandle() {
  const store = useStore();

  const loginState = computed(() => store.getters.loginState);

  const menuState = computed(() => store.getters.menuState);

  const stateHandle = (type, bool) => {
    store.dispatch(type, bool);
  };

  return { loginState, menuState, stateHandle };
}

我們可以在這個 useStateHandle.js 裡面使用 computed 跟 getters 的方式取得我們 store 的資料,以及建立一個 function 去執行dispatch ,透過帶入的type參數,來決定執行哪個 actions,最後都return 出去。

我們Vuex完全不用改變任何東西,接下來我們來看一下

Header.vue

<script>
import { useStateHandle } from "@/composition-api/useStateHandle.js";
export default {
  setup() {
    const { loginState, menuState, stateHandle } = useStateHandle();
    return {
      loginState,
      menuState,
      stateHandle,
    };
  },
};
</script>
<template>
  <header>
    <nav>
      <a @click="stateHandle('handleMenuState', !menuState)">Menu</a>
      <a @click="stateHandle('handleLoginState', !loginState)">Login</a
    </nav>
  </header>
</template>

我們可以看到原本寫的那些 store 的 code 全部不見了,只剩下我從 useStateHandle 裡面取出來的參數,透過我包裝好的 stateHandle,我可以帶入我想執行的 actions 的名稱,然後跟參數,就可以操作執行 Vuex 裡面 state。

Login.vue

<script>
import { useStateHandle } from "@/composition-api/useStateHandle.js";
export default {
  setup() {
    const { loginState } = useStateHandle();
    return { loginState };
  },
};
</script>
<template>
  <div :class="['login', { active: loginState }]">
    <h1>Login Page</h1>
  </div>
</template>

SlidMenu.vue

<script>
import { useStateHandle } from "@/composition-api/useStateHandle.js";
export default {
  setup() {
    const { menuState, stateHandle } = useStateHandle();
    return { menuState, stateHandle };
  },
};
</script>
<template>
  <div :class="['slid_menu', { active: menuState }]">
    <a class="close" @click="stateHandle('handleMenuState', false)">
      <img src="../assets/close.svg" />
    </a>
    <nav>
      <a>ABOTU</a>      
       <!-- 以下省略 -->
    </nav>
  </div>
</template>

這樣我們就可以減少從 Vuex 取的 state 的重複邏輯,以及我們要執行 actions 的 function,可以說是code少了非常多,我們開發網站的時候常常會有很多這樣類型的邏輯是可以封裝的,除了今天介紹的以外,還可以封裝非同步的處理,也可以去對 scroll 軸或是 resize 等事件進行共用邏輯的抽出,可以說是 composition api 提供了非常大的便利性以及管理方式。

codesandbox 範例 : https://codesandbox.io/s/vue2-vuex-to-vue3-vuex-composition-api-c44cg
有興趣的朋友可以玩玩看

Mike Vue

那如果對於Vue3不夠熟的話呢?

Ps. 購買的時候請登入或註冊該平台的會員,然後再使用下面連結進入網站點擊「立即購課」,這樣才可以讓我獲得更多的課程分潤,還可以幫助我完成更多豐富的內容給各位。

我有開設了一堂專門針對Vue3從零開始教學的課程,如果你覺得不錯的話,可以購買我課程來學習
https://hiskio.com/bundles/9WwPNYRpz?s=tc

那如果對於JS基礎不熟的朋友,我也有開設JS的入門課程,可以參考這個課程
https://hiskio.com/bundles/b9Rovqy7z?s=tc

訂閱Mike的頻道享受精彩的教學與分享

Mike 的 Youtube 頻道
Mike的medium
MIke 的官方 line 帳號,好友搜尋 @mike_cheng


上一篇
[重構倒數第26天] - 你可能不需要Vuex (You might not need Vuex)
下一篇
[重構倒數第24天] - You should use Skeleton
系列文
[ 重構倒數30天,你的網站不Vue白不Vue ] 32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言