💫

Vue2からVue3への変化と慣れていくためのTips

2022/11/24に公開

モチベーション

  • Vue2系サポート終了(23年末予定)を踏まえて、今後はVue3に触れる機会が増えそう
  • 現在Vue2を使っているけどVue3へリファクタする予定があり、慣れていく必要が出てきた

記事の内容

  • Vue3を取り巻く環境とかエコシステムなど整理
  • Vue3に慣れる為に知っておくべきことを整理
  • 移行に伴う破壊的変更の内容などは記載してない
  • ある程度Vue2を触った事があるのを前提で書いてる部分が多いです

なぜVue3に慣れる必要があるのか

1. Vue2のサポート終了

Vueの公式によるとVue2系が2023年の末に終了されることが告知されています。
Vue2系は2022年6月にリリースされた2.7系が最後で、今後は新しい機能などは追加されず、セキュリティ対応など最低限のアップデートのみの対応となります。
それに伴ってVue2からVue3へリファクタ等の対応する必要があります。

2. Vue2とVue3の書き方が大きく異なる

Vueではバージョンや環境によって書き方が大きく変わっています。

まず、Vue2ではOptions APIという書き方が主流でした。

Options API
<script>
export default Vue.extend({
   name: "App",
  components: {
  },
  data() {
    return {
    };
  },
  methods: {
  },
  watch: {
  },
});
</script>

Vue.extendの中にcomponentsmethods毎に処理を記述する方法で、Vueでネット検索するとよく見る書き方です。

この書き方はVue3でも互換性があるのですが、Vue3での主流な書き方ではないです。

さらにOptions APIのもう一つの書き方で、クラスコンポーネントという書き方もあります。

Options API(クラスコンポーネント)
<script lang="ts">
import Component from "vue-class-component";
import Vue from "vue-property-decorator";

@Component
export default class extends Vue {}
</script>

クラス構文を利用する書き方です。Vue.jsでTypeScriptを導入している場合によく見る書き方です。

一方、Vue3ではComposition APIが主流となっています。

Composition API(Vue3.2〜)
<script setup lang="ts">
import {ref} from "vue";

const exampleNo = ref(100) // Options APIのdataに該当

// Options APIのmethodsに該当
const addExampleNo = (): void => exampleNo++

// Options APIのcomputedに該当
const hogehoge = computed(
  (): number => {
    return exampleNo * 2
  }
)
</script>

Composition APIではスクリプトタグの中でsetupを記述する上記の書き方が主流です。

しかし、Vue3.2系以前はsetup()関数を使った下記の様な書き方も見かけます。

Composition API(Vue3.2未満)
<script lang="ts">
import { defineComponent, ref, } from "vue";

export default defineComponent({
  name: "App",
  setup() {
    const exampleNo = ref(100) // Options APIのdataに該当

    // Options APIのmethodsに該当
    const addExampleNo = (): void => exampleNo++

    // Options APIのcomputedに該当
    const hogehoge = computed(
      (): number => {
        return exampleNo * 2
      }
    );
  
  return { exampleNo, addExampleNo, hogehoge }
  }
})
</script>

setup()関数を使う場合だと<script lang="ts">の部分にsetup属性が付与されていません。

Vue3では上記の書き方を見かけることもありますが、コードの記述量も多くなりがちで、Vue3.2系以降では<script setup lang="ts">のようにスクリプトブロックにsetup属性を付与して書くのが主流です。

気をつけないといけない事は、Vueで調べ物をするときや教材でソースコードを見るときに、どの書き方で書かれているのかを最初に確認する事です。上記の書き方について、ざっくりと知っているだけでも理解が進みます。

この記事ではComposition API(3.2〜)での書き方で示していきます。

Vue3のエコシステム

以下の表はVue2とVue3で利用する主なライブラリ等の一覧です。

Vue2 Vue3 主な用途
バンドルツール VueCLI create-vue 実行のためのファイル変換
コード補完 Vuter Volar Vueコードの補完
ルーティング Vue Router 3 Vue Router 4 SPAの作成
状態管理 Vuex Pinia コンポーネント間のデータを管理する
UIライブラリ Vuetify2 Vuetify3 UIの提供

(*vue3に記載しているエコシステムもvue2系で使えるものもあります)

上記の表からエコシステムはVue2から多くのものが置き換えられているのが分かります。

更に、これらは正式版としてVue3に対応するようになりました(2022年11月時点)

VueはTypeScriptと相性が悪いと言われていましたが、Vue3自体がTypeScriptで一新されたのと、付随するエコシステムもTypeScriptに準拠しているため、TypeScript絡みで悩まされる事はほぼ無くなった印象です。

また、Vue自体の話にはなるのですが、個人的にVue3のsetup関数に慣れなかった部分がありました。
ところが、Vue3.2から使えるsetupをスクリプトタグ内で記述できるようになった事でコード量も減り、見通しもよくなった事でかなり書きやすくなりました。
世間ではReactが優勢な空気がありますが、Vue3も検討に上がるレベルで安定した段階になっていると個人的には思います。

Vue3を使ってみる

新規プロジェクトの作成

Vue3でプロジェクトを新規で作成する時はcreate-vueを使います。

create-vueはVue公式のプロジェクトを作成するためのライブラリです。

今までVueのプロジェクトを作成するときはvue CLIを利用していたのですが、create-vueが登場したことにより、vue CLIはメンテナンスモードになりました。

作成するときはコマンドラインから

npm init vue@latest

を入力します。

TypeScriptやPiniaはYesを選択します。

インストールが完了したら、以下のコマンドを入力してプロジェクトを立ち上げます。

  cd vue3-example-app
  npm install
  npm run dev

create-vueではViteが使われている

create-vueでVueプロジェクトを作成すると、バンドルツールとして自動的にViteが利用されます。

vue CLIではWebpackを利用して各ファイルのバンドルを行い、ブラウザで実行可能なファイルに変換を行なっていましたが、実行速度が課題となっていました。

この速度を解決するために、create-vueは従来のWebpackからViteへバンドルツールの変更が行われています。

Viteではコード変更を行った際も反映の速さを実感できるくらい違うので、納得できます

(VScodeを使っている場合)拡張機能をインストール

vue3のコーディング用に使われる拡張機能でVolorをインストールします。

過去vue2を使っている場合はVuterが既にインストールされている可能性があるので、インストール済みからVuterがないか探します。

もしある場合は、無効にする(ワークスペース)を選択して、Vuterを利用を使わないようにします。

以上でVue3が記述できるようになりました。

Vuetify3

VueのUIライブラリであるvuetifyもつい最近(2022年11月)バージョン3系がリリースされました。

せっかくなので、vuetify3もインストールしてみます。

すでにVueのプロジェクトは作成しているので、Manual stepsに沿ってVuetify3を追加します。

https://next.vuetifyjs.com/en/getting-started/installation/#manual-steps

インストールと設定が完了したらv-btnなど気になるコンポーネントを表示してみましょう

VueRouter4

vueRouterを使う事で画面遷移(いわゆるSPA)を簡単に行うことができます。

プロジェクト作成時にVueRouterを追加しているため、コードを追加するだけです。

  • router.tsにsampleへのルーティングを追加
  • 対応するコンポーネントを作成

これでルーティングを行うことができます。

  • View
views/SampleView.vue
<template>
  <div>
    <h1>Vue3の練習</h1>
  </div>
</template>
  • Component
components/SampleView.vue
<script setup lang="ts">
</script>
<template>
  <v-container>
    <v-row>
      <v-col cols="12">
        <v-btn>Vuetifyで記述</v-btn>
      </v-col>
    </v-row>
  </v-container>
</template>

router.tsにsampleへのルーティングを追加します。

router/index.ts
import { createRouter, createWebHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    // 省略、以下追加する
    {
      path: "/sample",
      name: "sample",
      component: () => import("../views/SampleView.vue"),
    },
  ],
});

export default router;

最後にApp.vueにsampleへ移動するリンクを追加します。

App.vue
<nav>
  <RouterLink to="/">Home</RouterLink>
  <RouterLink to="/about">About</RouterLink>
  <RouterLink to="/sample">Sample</RouterLink> // 追加
</nav>

Pinia

PiniaはVueの公式ライブラリである状態管理ライブラリです。

以前の状態管理ライブラリであったVuexと似ていますが、PiniaではTypeScriptをサポート、mutationを廃止し、値を更新する際もcommitではなくactionsから呼び出す形になり、Composition APIで記述しているのと変わらない感覚で状態管理を記述できるようになりました。

Piniaではstoreファイル内にtsファイルを作成しdefineStoreをインポートし記述します。

store/sample.ts
import { defineStore } from "pinia";

export const useCounterStore = defineStore({
  state: () => {
    // データの本体
  },
  getters: {
    // データの加工処理
  },
  actions: {
    // データの変更処理
  }
})

上記の例のように、データそのものはstateで管理します。

stateに保存されたデータに対して、gettersにてデータの加工処理も行えます。

また例ではuseCounterStoreだけを定義していますが、tsファイル内で複数定義する事も可能です。

Vue3で抑えておきたいこと

Vue3においてよく使う書き方で、Vue2と大きく変わった部分をまとめました。

Vue3の変更点はたくさんありますが、初見でも混乱しないようによく使う書き方に絞ってまとめています。

ref,reactive

Vue3ではリアクティブな値(vue2でいうdata)はrefreactiveを使います。

Vue2からの初見ではconstに続けて書いていたりしているので違和感を持ちますが、慣れるとすぐリアクティブな値であると分かります。

ref
<script setup lang="ts">
import { ref } from "vue";
const hogehoge:number = ref(0)
</script>
<template>
 <div>{{ hogehoge }}</div>
</template>

オブジェクトの場合はreactiveが使われることが多いです。

reactive
<script setup lang="ts">
import { reactive } from "vue";
const hogehoge = reactive({ title: "" , name: "" });
</script>
<template>
 <div>{{ hogehoge }}</div>
</template>

コンポーネントの呼び込み

vue3では別コンポーネントをインポートするとき、componentsにコンポーネント名を記述する必要がなくなりました。

<script setup lang="ts">
import SampleComponent from ./SampleComponent.vue;
</script>

<template>
 <SampleComponent />
</template>

記述量が減り、importだけで済むので分かりやすく明確になりました。

watchEffect()

  • watchEffectはVue3から登場した新しい記法です。watchと似ていますが、監視対象を指定しません。refやreactiveでリアクティブにした変数のどれかが変更したときに実行をしてくれます。
components/SampleView.vue
<script setup lang="ts">
import { watchEffect, ref } from "vue";

const count = ref(0);
const addCount = () => count.value++;
watchEffect(() => console.log(`クリックした回数:${count.value}`));
</script>

<template>
  <v-container>
    <v-row>
      <v-col cols="12">
        <v-btn @click="addCount">数字を増やす</v-btn>
      </v-col>
    </v-row>
  </v-container>
</template>

ライフサイクルフック

ライフサイクルフックでは読み込み時やレンダリング時などに処理を実行する関数です。

vue2の書き方
<script>
export default {
  created() { 
    console.log('createdが実行されました')
  }
}
</script>

特筆すべきなのは、Vueアプリケーションの初期化処理後に実行するbeforeCreatecratedを明示する必要が無くなった所です。

これはComposition APIでは<script setup>内に記述したものについては全てbeforeCreatecrated間で実行されるため、わざわざ呼び出す必要が無くなったためです。

また、その他のライフサイクルでは明示的に書く必要がありますが、微妙に書き方が変わっているので注意が必要です。

Vuu2(Options API) Vue3(Composition API)
beforeCreate -
created -
beforeMount onBeforeMount()
mounted onMounted()
beforeUpdate onBeforeUpdate()
updated onUpdated()
beforeDestroy onBeforeMounted()
destroyed onUnmounted()

Composition APIでは接頭にonをつけています。なおdestroyedに限ってはonを付けずにonUnmountedとしています。

最後に

Vue3ではエコシステム含め開発しやすい環境が整ってきました。

今後はVue3を書く機会も増えてくるはずなので慣れていきたいです。

Discussion