2021.03.22

Vue Composition API移行メモ

vue v3系からComposition APIが仲間入りするらしい。 vue v2でもpluginとしてcomposition apiが利用できるので使ってみる。 従来のvueのlifecycleがだいぶ変わる。react hooksやflutterのriverpodとかそっち系の状態管理デザインパターンのvueバージョンみたいな雰囲気と理解。時代の流れ。


概要ざっと

<template lang="pug">
  .home
    p {{clickCntChunk.Count.value}} is {{clickCntChunk.Message.value}}
    button(@click="clickCntChunk.ClickedHandler") increment
    p.blue {{testAnotherComputedMessage}}
    //- HelloWorld(msg="Welcome to Your Vue.js + TypeScript App")
</template>
<script lang="ts">
import {
  defineComponent,
  reactive,
  ref,
  computed,
  watch,
  onMounted,
} from '@vue/composition-api';

function ClickCntChunk() {
  const Count = ref<number>(0);
  const IsOdd = computed((): boolean => {
    return Count.value % 2 != 0;
  });
  const Message = computed((): string => {
    return IsOdd.value ? 'ODD' : 'EVEN';
  });
  const DidMounted = (): void => {
    console.log('did mounted');
  };
  const ClickedHandler = (): void => {
    console.log('clicked!!');
    Count.value++;
  };

  return {
    Count,
    IsOdd,
    Message,
    ClickedHandler,
    DidMounted,
  };
}

export default defineComponent({
  setup() {
    // Test Composition API
    const clickCntChunk = ClickCntChunk();

    const testAnotherComputedMessage = computed((): string => {
      return clickCntChunk.IsOdd.value ? 'Odd Message' : 'Even Message';
    });

    const testSomethingFunc = (newValue: boolean, oldValue: boolean): void => {
      console.log(`old : ${oldValue}, new : ${newValue}`);
    };

    // life cycles
    onMounted(() => {
      clickCntChunk.DidMounted();
    });

    watch(clickCntChunk.IsOdd, testSomethingFunc);

    return {
      clickCntChunk,
      testAnotherComputedMessage,
    };
  },
});
</script>

グワっとみてもらえればvueを使ったことある人はわかると思うが、 mountedやcomputedなど従来一つのvue templateに紐づいていたものをモジュールにして外に出せる。 従来もmixinや別コンポーネントを利用するなどして似たようなことは実現できていたが、 結局一つのvue tempalteが肥大化するという事態に陥った経験があるのではないだろうか。 methodsやcomputedの下に機能が違う別々の変数をアサインして長くなりスクロールやら画面分割やらで凌いでた事がなくなるっていう開発のうざったらしさが解消されるのは嬉しい。 もちろんコーディングのデザインがよくなる意味がある。良い気がする。


Ref, Reactive

データをバインドする時に使う。 普通の値にはref使えば良い。 配列とかオブジェクトの中身の変化も監視したい時はreactive使う。

import { ref, reactive } from 'vue'

~~~
setup(){
  const count = ref<number>(0);
  const isOdd = computed(count,()=>{
    return isOdd % 2 == 0
  })
  const state = reactive({
    count: 0
  })
}

router

routerからモジュールとして利用する。

import { useRouter, useRoute } from 'vue-router';

~~~
setup() {
  const router = useRouter()
  const route = useRoute()
}

vuex

これもrouterと同じような感じ。モジュール使う。

import { useStore } from 'vuex';

~~~
setup() {
  const store = useStore();
}
./src/store/index.ts
import { createStore } from "vuex";

export default createStore({
  state: {
    IsLoading: false
  },
  mutations: {
    SetLoad(state, flag){
      state.IsLoading = flag
    }
  },
  actions: {
    SetLoad: ({commit}, flag) => commit('SetLoad', flag)
  },
  modules: {},
});
./src/main.ts
import store from './store';

app.use(store).mount('#app');