[重构倒数第25天] - Vuex + Composition API 组合技

前言

该系列是为了让看过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


<<:  Day-6 Excel以等比级数填满!?

>>:  Day 06 Flex message simulator- 美化自己的chatbot

JS 30 - 将 JSON 资料应用到统计学!

大家好! 今天我们要实作解析 JSON 资料,并计算资料的变异数。 我们进入今天的主题吧! 公式 母...

Day2 帐号申请与管理

访问控制(RAM)是什麽? 访问控制(Resource Access Management,RAM)...

Day03:小姐,你手上那是什麽?

昨天提到了一个奇怪的现象: byte num = 128; 如上撰写,你的IDE将会在128底下亮出...

使用 Template Message 替 Line Bot 加上同意条款的功能(2)

昨天我们完成了 user sheet 的 query & upsert 功能,今天就要正式将...

[Day 27] Node thread pool 2

前言 昨天聊到了 TP 告知 main Thread 任务完成的方法。今天说说 TP 本身在运行甚麽...