CodeZine(コードジン)

特集ページ一覧

新Vue.js「Vue 3」でコンポーネント実装法を大きく変える「Composition API」

JavaScriptフレームワーク「Vue 3」の新機能紹介 第1回

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

 「Vue 3」は、JavaScriptフレームワーク「Vue.js」の次期バージョンで、2016年にリリースされた「Vue 2」以来のメジャーバージョンアップです。本記事では、Vue 3で導入される新機能のうち、新しいコンポーネント記述形式「Composition API」を説明していきます。

目次

はじめに

 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のコマンドを実行します。

[リスト1]Vue CLIでVue 3対応プロジェクトを生成するコマンド
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/合計の機種数も表示されます。以下ではこのサンプルを複数の方法で実装していきます。

図1 Composition APIの利用法を説明するサンプル
図1 Composition APIの利用法を説明するサンプル

Options APIを利用した実装

 図1のサンプルを、従来のOptions APIで実装した例を、リスト2に示します。

[リスト2]Options APIの実装(p001-options/src/components/Phones.vue)
<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に示します。

[リスト3]Composition APIの実装(p002-composition/src/components/Phones.vue)
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のプロパティでコンポーネントのデータを参照します。

[リスト4]reactive利用時の<template>部での変数参照(p002-composition/src/components/Phones.vue)
<li v-for="(elem, index) in state.iOS" v-bind:key="index">
  {{ elem }}
</li>

refを利用した変数の記述

 reactiveメソッドでは複数の変数をまとめて設定しましたが、リスト5の通り、各変数をrefメソッドで設定する記述方法もあります。

[リスト5]refを利用した記述(p003-ref/src/components/Phones.vue)
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と比較してください)。

[リスト6]ref利用時の<template>部での変数参照(p003-ref/src/components/Phones.vue)
<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する方法がおすすめです。

[リスト7]toRefsメソッドの利用例(p004-torefs/src/components/Phones.vue)
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メソッドが返却する変数の配列から各要素を取り出すために利用されています。


  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト  吉川 英一(ヨシカワ エイイチ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

バックナンバー

連載:JavaScriptフレームワーク「Vue 3」の新機能紹介
All contents copyright © 2005-2020 Shoeisha Co., Ltd. All rights reserved. ver.1.5