Vue 2(vue.jsのバージョン2)で作成したコードをVue 3(バージョン3)の新機能であるVue Composition APIを使用した方法に書き換えを行うことでVue Composition APIの記述方法を確認していきます。

書き換えに利用するのは頻繁にプログラミングの例で活用されるTodoリストアプリケーションです。身近で馴染みのあるコードを利用することでComposition APIではどのような書き換えが必要なのかを短時間で理解することができます。

Vue 3はまだリリースされていないためVue 2のComposition APIを追加でインストールします。またVue 3でもこれまでのようにCompositon APIを利用しない記述も可能です。これまでの記述方法をoptions(API or based)と呼んでいます。2020年8月ではVue CLIをバージョンアップするとVue3を選択することが可能なので追加でComposion APIをインストールする必要はなくなりました。

vueプロジェクトの作成

vue createコマンドでvueのプロジェクトを作成します。今回はComposition APIのみ注目するためインストールのオプションはデフォルトのままで行います。


 $ vue create test_composition_api

Composition APIパッケージのインストール

Composition APIはVue 3から利用できる新機能ですがパッケージを追加することでVue 2でも利用することができます。

プロジェクト作成後、npmコマンドを利用してComposition APIパッケージのインストールを行います。


 $ npm add @vue/composition-api

Todoリストのコード

input要素にTodoを入力して追加ボタンを押すと追加ボタンの下にTodoがリスト化されて表示されているというシンプルなコードです。追加したTodoは右側に表示されるXをクリックするとリストから削除することができます。

Todoリストの動作確認
Todoリストの動作確認

<template>
  <div id="app">
    <h1>Todoリスト</h1>
    <input v-model="todo"><br>
    <button @click="addTodo">追加</button>
    <ul>
      <li v-for="(todo, index) in todos" :key="index">{{ todo }} <span @click="removeTodo(index)">X</span></li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      todo: '',
      todos:[]
    }
  },
  methods: {
    addTodo() {
      this.todos.push(this.todo)
      this.todo = ''
    },
    removeTodo(index) {
      this.todos.splice(index, 1)
    }
  }
}
</script>

<style>
</style>

Composition APIを利用した記述

Compositino APIを利用するためmain.jsファイルでCompositionAPIのimportを行います。


import Vue from 'vue'
import App from './App.vue'
import CompositionApi from '@vue/composition-api' //追加

Vue.config.productionTip = false
Vue.use(CompositionApi) //追加

new Vue({
  render: h => h(App),
}).$mount('#app')

setup関数の追加

JavaScriptのコードから変更を行なっていきます。まずはscriptタグの中にsetup関数を追加します。setup関数はコンポーネント内でComposition APIを使用するために必要な関数です。setup関数の中にデータプロパティや関数を追加していきます。


<script>
export default {
  setup() {
  // データプロパティや関数を追加
 }
}
</script>

データプロパティをreactiveを利用して設定

これまでdataプロパティ内で設定していた変数はreactiveを利用して行います。reactiveを設定したstateはsetup関数の中でオブジェクトの中に入れてreturnする必要があります。returnしたsateはHTML側のtemplateタグの中でアクセスが可能となります。


import { reactive } from "@vue/composition-api";
export default {
  setup() {
    const state = reactive({
      todo: '',
      todos: []
    })
    return {
      state,
    }
  }
}
}

これまでの記述方法ではHTML側ではtodoと記述することでtodoの値を表示することができました。Compostion APIではstate.todoと記述する必要があります。次の章で確認を行います。

reactiveではじめてのHello World

まず最初にreactiveを利用してmessageプロパティに設定したHello Worldをブラウザに表示させてみましょう。 Compostion API を利用した場合はmessageではなくstate.messageと設定する必要があります。


<template>
  <div id="app">
    {{ state.message }}
  </div>
</template>

<script>
import { reactive } from "@vue/composition-api";
export default {
  setup() {
    const state = reactive({
      message: 'Hello Wold'
    })
    return {
      state,
    }
  }
}
</script>

ブラウザで確認するとHello Worldが表示されたらComposition APIが動作していることがわかります。

Composition APIでHello World!
Composition APIでHello World!

refを利用してHello World

データプロパティを設定する場合にreactiveだけではなくrefを利用することもできます。

refを利用する場合はreactiveと同様にrefをimportし、refの引数にHello Worldとそのまま値を入れます。HTML側で表示させたい場合はそのまま{{ message }}と記述することができます。reactiveを使用した場合と異なり、state.messageと記述する必要ありません。


<template>
  <div id="app">
    <h1>{{ message }}</h1>
  </div>
</template>

<script>
import { ref } from "@vue/composition-api";
export default {
  setup() {

    const message = ref('Hello World')

    return {
      message
    }
  }
}
</script>

reactiveからrefへの変換

reactiveを利用するとtemplate側ではmesssgeにアクセスするためにstateを必ずをつける必要がありますが、refの場合はstateは必要ではなくmessageと直接記述することができます。toRefsというメソッドを利用するとreactiveをrefsに変換することができます。


<template>
  <div id="app">
    <h1>{{ message }}</h1>
  </div>
</template>

<script>
import { ref } from "@vue/composition-api";
export default {
  setup() {
    const state = reactive({
      message: 'Hello Wold'
    })
    return {
      ...toRefs(state),
    }
  }
}
</script>

関数の設定

Vue 2まではmethodsの中で関数を追加してきましたが、setupの中で直接関数を設定することができます。設定した関数はstateと同様にsetup関数の中でreturnする必要があります。下記ではaddTodo, removeTodoの2つの関数を追加設定しstateを合わせたオブジェクトをreturnしています。


import { reactive } from "@vue/composition-api";
export default {
  setup() {
    const state = reactive({
      todo: '',
      todos: []
    })

    const addTodo = () => {
      state.todos.push(state.todo)
      state.todo = ''
    }

    const removeTodo = index => state.todos.splice(index,1)
    
    return {
      state,
      addTodo,
      removeTodo
    }
  }
}

これでJavaScript側での書き換えは完了です。

HTML側の更新

JavaScript側の更新が完了したので次はtemplateタグ内のHTML文の更新を行っていきます。

reactiveのHello Worldの表示の部分で少し説明を行いましたが、todoをHTML側で表示させたい場合はstate.todoと設定を行う必要があります。

各変数の前にstateを追加すると下記のようになります。


<template>
  <div id="app">
    <h1>Todoリスト</h1>
    <input v-model="state.todo"><br>
    <button @click="addTodo">追加</button>
    <ul>
      <li v-for="(todo, index) in state.todos" :key="index">
        {{ todo }} <span @click="removeTodo(index)">X</span>
      </li>
    </ul>
  </div>
</template>

これで最初に記述したCompositon APIを使用しないコードからCompositon APIを使用したコードへの書き換えは完了です。

Computedプロパティの使い方

Vue 2での記述方法

Composition APIでのComputedプロパティの使い方を確認します。Vue 2では、Computedプロパティを使ってリストの長さを取得したい場合は下記のように行います。


  computed: {
    getListLength() {
        return this.todos.length
    }
  },

HTML側では設定したcomputedプロパティを下記のように設定します。


<h1>Todoリスト2 {{ getListLength }}</h1>
Computedプロパティでリストの大きさを表示
Computedプロパティでリストの大きさを表示

Composition APIを利用した場合

Composition APIを利用してComputedプロパティを設定する場合はcomputedをimportする必要があります。


import { reactive, computed } from "@vue/composition-api";

reactiveと関数を利用してComputedプロパティを利用することができます。

reactiveを利用する場合

reactiveを利用する場合は下記のようにgetListLengthを追加し、computedの中に実行したい関数を設定します。


setup() {
  const state = reactive({
    todo: '',
    todos: [],
    getListLength: computed(() => state.todos.length)
  })

HTML側のComputedプロパティの結果を表示させたい場所にはstate.getListLengthのようにstateをつける必要があります。


<h1>Todoリスト {{ state.getListLength }}</h1>

関数を利用する場合

addTodoやremoveTodoのように追加を行います。


const getListLength = computed(() => state.todos.length)

関数として追加した場合は、setup関数の中のreturnに追加する必要があります。


    return {
      state,
      addTodo,
      removeTodo,
      getListLength
    }

HTML側では先程のreactiveのようにstateを付与する必要はないのでそのままgetListLengthを設定することができます。


<h1>Todoリスト {{ getListLength }}</h1>

他のコンポーネントをimport

他のコンポーネントをimportしたい場合はこれまでと同様の方法でimortすることができます。componentsディレクトリにあるHelloWorldをimportとしています。


import HelloWorld from "@/components/HelloWorld"
export default {
  components: { HelloWorld },
 setup() {
  //略