はじめに
Vue.jsは、Webページのユーザーインタフェース(UI)を構築できるフレームワークです。2015年のバージョン1(Vue 1)、2016年のバージョン2(Vue 2)に続き、バージョン3(Vue 3)が開発中で、2020年第2四半期にリリース予定です。
本記事では、全2回にわたって、Vue 3の新機能を紹介していきます。今回は、Vue 3で導入されるコンポーネントの新しい記述形式「Composition API」を説明していきます。
対象読者
- Vue 3の概要を把握したい方
- 新しいライブラリーを試してみたい方
- これからVue.jsをプロジェクトに採用する予定の方
必要な環境の準備
本記事のサンプルコードは、以下の環境で動作を確認しています。
Windows 10 64bit版
- Node.js v10.18.1 64bit版
- Vue.js 3.0.0-beta.15
- Vue CLI 4.4.4
- Microsoft Edge 83.0.478.54
サンプルコードを実行するには、サンプルのフォルダーで「npm install」コマンドを実行してライブラリーをダウンロード後、「npm run serve」コマンドを実行して、Webブラウザーで「http://localhost:8080/」を開きます。
Vue 3対応プロジェクトを生成する方法
CLIツール「Vue CLI」を利用すると、Vue.jsのプロジェクトを生成できます。Vue CLIは、「npm install -g @vue/cli」コマンドでインストールできます。Vue CLIでVue 3対応プロジェクトを生成するには、リスト1のコマンドを実行します。
vue create <プロジェクト名> # Vue CLIでプロジェクトを生成 ...(1) cd <プロジェクト名> # プロジェクトのフォルダーに移動 ...(2) vue add vue-next # プロジェクトをVue 3対応 ...(3)
(1)でプロジェクトを生成します。vue createコマンドではプロジェクトの設定を対話的に選択できますが、本記事ではデフォルト設定(default)を利用します。(2)でプロジェクトのフォルダーに移動後、(3)でプロジェクトをVue 3対応にします。
新しいコンポーネント記述形式「Composition API」
Composition APIは、Vue.jsにおけるコンポーネントの新しい記述形式です。Vue 2ではプラグインとして提供されていましたが、Vue 3では標準になりました。従来のコンポーネント記述形式(Options API)は、データ/メソッド/算出プロパティの単位で記述するため、複数機能の実装がコードの各所に分散したり、ロジックの再利用が難しかったりしました。Composition APIはこれらの問題を解決します。
Composition APIの利用法を、図1のサンプルで説明します。このサンプルでは、iOSとAndroidのスマートフォン機種リストを表示します。画面下部のテキストボックスに機種名を入力して「追加」をクリックするとリストに追加されます。iOS/Android/合計の機種数も表示されます。以下ではこのサンプルを複数の方法で実装していきます。
Options APIを利用した実装
図1のサンプルを、従来のOptions APIで実装した例を、リスト2に示します。
<template> <div> <h4>iOS: {{ countIOS }} 機種</h4> <ul> <li v-for="(elem, index) in iOS" v-bind:key="index"> {{ elem }} </li> </ul> (略:Android機種数とリスト、総機種数) <div> <input v-model="newIOS" placeholder="iOS機種"> <button @click="addNewIOS">追加</button> </div> (略:Android機種のテキストボックスと追加ボタン) </div> </template> <script> export default { // データ ...(1) data() { return { iOS: ['iPhone 11'], // iOS機種のリスト newIOS: '', // iOS機種のテキストボックス内容 android: ['Galaxy S20 5G'], // Android機種のリスト newAndroid: '' // Android機種のテキストボックス内容 } }, // メソッド ...(2) methods: { // iOS機種を追加 addNewIOS() { this.iOS.push(this.newIOS) this.newIOS = '' }, (略:Android機種を追加するaddNewAndroid) }, // 算出プロパティ ...(3) computed: { // iOS機種数 countIOS() { return this.iOS.length }, (略:Android機種数を取得するcountAndroid、総機種数を取得するcountTotal) } } </script>
<template>部で参照するデータは(1)のdataに記述します。ここではiOS、Android機種のリストと、テキストボックス内容を格納する変数を記述しています。追加ボタン押下時に機種リストに追加する処理を行うメソッドは(2)のmethodsに、iOS/Android/総計の機種数を取得する算出プロパティは(3)のcomputedに記述します。
このようにOptions APIでは、data/methods/computedといった単位で記述するため、iOS関連とAndroid関連の各実装がコード内に分散してしまいます。また、iOSとAndroidの処理は似通っていますが、Options APIの枠組みのため、共通化が難しくなっています。
Composition APIを利用した実装
リスト2と同じ内容をComposition APIで実装した<script>部を、リスト3に示します。
export default { // コンポーネント設定処理 ...(1) setup() { // reactiveでデータを記述 ...(2) const state = reactive({ iOS: ['iPhone 11'], newIOS: '', android: ['Galaxy S20 5G'], newAndroid: '' }) // メソッド ...(3) function addNewIOS() { state.iOS.push(state.newIOS) state.newIOS = '' } (略:Android機種を追加するaddNewAndroid) // 算出プロパティ ...(4) const countIOS = computed(function() { return state.iOS.length }) (略:Android機種数を取得するcountAndroid、総機種数を取得するcountTotal) // ここまで定義してきた内容を返却 ...(5) return { state, addNewIOS, addNewAndroid, countIOS, countAndroid, countTotal } } }
コンポーネントの設定は(1)のsetupメソッドに記述します。<template>部で参照するデータは(2)の通り、reactiveメソッドの引数にデータ変数を指定して記述します。reactiveメソッドに指定された変数は、メソッドが返却するstate変数のプロパティとなり、値の変更が画面に反映されるようになります。
メソッド(3)はJavaScriptの標準的な記法で記述します。また、算出プロパティ(4)は、算出処理を実装したfunctionをcomputedメソッドの引数に与えて記述します。メソッドや算出プロパティでデータを参照/操作する場合、stateのプロパティ(「state.<変数名>」)を利用します。(5)で、<template>部で利用するstate/メソッド/算出プロパティをreturnします。
reactiveメソッドを利用する場合、<template>部ではリスト4の「state.iOS」のように、stateのプロパティでコンポーネントのデータを参照します。
<li v-for="(elem, index) in state.iOS" v-bind:key="index"> {{ elem }} </li>
refを利用した変数の記述
reactiveメソッドでは複数の変数をまとめて設定しましたが、リスト5の通り、各変数をrefメソッドで設定する記述方法もあります。
setup() { // refでデータを記述 ...(1) const iOS = ref(['iPhone 11']) const newIOS = ref('') const android = ref(['Galaxy S20 5G']) const newAndroid = ref('') // メソッド ...(2) function addNewIOS() { iOS.value.push(newIOS.value) newIOS.value = '' } (略:addNewAndroidメソッド、算出プロパティ) // ここまで定義してきた内容を返却 ...(3) return { iOS, newIOS, android, newAndroid, (略:メソッド、算出プロパティ) }
(1)で、refメソッドの引数に初期値を与えて各変数を記述します。メソッドや算出プロパティで変数を参照/操作するには、(2)の通り、各変数のvalueプロパティ(「<変数名>.value」)を利用します。最後に(3)で各変数をreturnします。
reactiveメソッドの場合と異なり、refメソッドを利用する場合、<template>部ではリスト6の「iOS」のように、変数そのものを記述できます(リスト4と比較してください)。
<li v-for="(elem, index) in iOS" v-bind:key="index"> {{ elem }} </li>
reactiveからrefへの変換
refを利用すれば、<template>部では(stateのプロパティではなく)変数そのものを参照できて記述がシンプルになりますが、<script>部では変数の参照/操作にvalueプロパティが必要となり、また、最後にすべての変数をreturnする必要があるため、変数の数が多い場合は記述が煩雑になります。
そのため、リスト7の通り、<script>部ではreactiveメソッドでstateを記述しておき、最後に(1)のtoRefsメソッドでrefに変換してreturnする方法がおすすめです。
setup() { // reactiveでデータを記述 const state = reactive({ iOS: ['iPhone 11'], newIOS: '', android: ['Galaxy S20 5G'], newAndroid: '' }) (略:メソッド、算出プロパティ) // ここまで定義してきた内容を返却 return { ...toRefs(state), // stateの内容をrefに変換 ...(1) (略:メソッド、算出プロパティ) } }
この場合、<script>部ではstateを利用しつつ、<template>部ではリスト6の通り変数を直接参照できるようになります。なお、リスト7(1)のtoRefsに付与されている「...」はスプレッド構文と呼ばれ、toRefsメソッドが返却する変数の配列から各要素を取り出すために利用されています。