VueUseはVue2/Vue3のComposition APIを使った場合にのみ利用可能なライブラリでライブラリの中にVue.jsでアプリケーションを構築する上で利用頻度の高いものから低いものまで便利な関数が多数含まれています。

VueUseの関数を見ていくと自作できそうなものも存在しますが200以上の関数が登録されているので今まで利用した経験がない人であれば利用可能な関数がないか一度目を通してみることをお勧めします。

本文書はVueUseを通してVueのComposables(コンポーザブル)の作成方法について説明を行なっており読み終えるとVueUseの使い方がわかるだけではなくComposablesな関数の作成方法も理解することができます。Composablesという言葉以外難解な単語も難しいコードも利用していないので安心して読み進めてください。

Composablesな関数はComposition APIを利用するのでComposition APIの基礎知識が必要となります。

Composablesな関数とは

Vue.jsではVueUseに含まれるような”再利用可能な関数”のことをComposablesな関数と呼びます。Composition APIを利用してコンポーネントからreactiveな変数とロジックを取り出して独立した関数として作成します。Composition APIでは Composablesな関数を作成することができるためVueUseのようなライブラリを作成することができます。Composablesという名前だけではどのようなものか分かりにくいのでもっと直感的にわかりやすい名前にしてもらいたいですが言葉の説明よりも実際にわかりやすい例でコードを確認することですぐに理解することができます。Composablesは一度作成するとプロジェクトを超えて再利用可能なので開発効率を上げることにもつながります。

Vue.jsのComposablesはReactのHooksに対応するのでHooksを使い慣れている人であればすぐに理解できると思います。

Vue 3の環境構築

VueUseの動作確認を行うためにVue 3のプロジェクトの作成を行います。プロジェクトの作成にはViteは利用します。下記のコマンドを実行することでvueuse-appという名前のフォルダが作成されます。


 % npm create vite@latest vueuse-app -- --template vue

> npx
> create-vite vueuse-app --template vue


Scaffolding project in /Users/mac/Desktop/vueuse-app...

Done. Now run:

  cd vueuse-app
  npm install
  npm run dev

作成されたvueuse-appに移動してnpm installコマンドを実行します。


 % cd vueuse-app 
 % npm install
Vueのビルドツールを利用したい場合はnpm create vue@latestのコマンドを実行してください。公式のプロジェクトの作成ツールのcreate-vueが実行され利用したい機能を選択してインストールを行うことができます。
fukidashi

npm installによるJavaScriptライブラリのインストール後にnpm run devコマンドを実行します。開発サーバが起動するのでhttp://localhost:5173アクセスすることができます。


 % npm run dev

> vueuse-app@0.0.0 dev
> vite


  VITE v5.3.5  ready in 853 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help
Vue+Viteの初期画面
Vue+Viteの初期画面

VueUseライブラリのインストール

Viteによるプロジェクトの作成と開発サーバの起動が確認できたのでVueUseライブラリのインストールを行います。


 % npm i @vueuse/core

vueuse/coreのインストールが確認したら動作確認で利用するライブラリとバージョンをpackage.jsonファイルで確認しておきます。vueuseのバージョンは10.11.0であることが確認できます。


{
  "name": "vueuse-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@vueuse/core": "^10.11.0",
    "vue": "^3.4.31"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.5",
    "vite": "^5.3.4"
  }
}

VueUseにどのような関数があるのか確認を行うためVueUseのサイトにアクセスします。画面中央にあるFunctionsをクリックすると関数の一覧ページに移動することができます。

VueUseのホームページ
VueUseのホームページ

本文書執筆当時には142の関数、現在は200以上登録されていますが日々関数の数は増えています。VueUseのベースとなるCoreに関しては用途に応じて大きく12個のカテゴリーに分かれています。Browserのカテゴリーにはイベントの追加・削除に利用できるuseEventListenerやElementsのカテゴリーには要素の移動に利用できるuseDraggableなどがあります。ほとんどの関数の名前の前にはuseがついています。

VueUseの関数一覧
VueUseの関数一覧

各関数のページにはデモ、利用例が記述されているので利用するためのハードルは高くありません。ページにはソースコードへのリンクもあり、それぞれの関数がどのように記述されているか読みことでスキル向上につながります。気になる関数はソースコードを読んでみることをお勧めします。

useDraggableのページ
useDraggableのページ

useCounter

シンプルな関数はたくさんありますがComposablesな関数を自作するための教材としてはuseCounter関数は非常にわかりやすいので今回はuseCounterを利用して動作確認を行っていきます。

VueUseの利用

ドキュメントの中には使用方法もオプションの利用方法も型の定義も記述されているので参考に設定を行っていきます。ドキュメントはこちらから確認できます。https://vueuse.org/shared/useCounter/#usecounter

App.vueファイルにvueuseのcoreからuseCounter関数をimportして動作確認を行ってみましょう。useCounter関数を利用することでカウンター機能を持たせることができます。カウンター頻繁に学習用に利用される機能なのでほとんどの方が作ったことがあるとは思います。ボタンをクリックするとカウント数が増えたり減ったりするカウンターです。

useCounterの引数にはカウントの初期値を指定することができ、戻り値の中からcount変数, inc関数, dec関数を利用しています。VueUseではimportした関数を実行し戻される変数や関数を利用することでimportしたコンポーネントでimportした関数が持つ機能を利用できるようになります。その他useCounterではget, resetなどの関数も戻されますが今回は利用しません。


<script setup>
import { useCounter } from '@vueuse/core';
const { count, inc, dec } = useCounter(0);
</script>

<template>
  <h1>VueUse: useCounter</h1>
  <div>Count:{{ count }}</div>
  <div>
    <button @click="inc()">increase</button>
    <button @click="dec()">decrease</button>
  </div>
</template>

countやinc, dec関数はAppコンポーネントで定義した場合と同様の方法で利用することができるのでincreaseボタンをクリックするとinc関数が実行されcountの数が増え、decreaseボタンをクリックするとdec関数が実行されcountの数が減ります。

useCounterを利用したカウント
useCounterを利用したカウント

useCounterの使用方法と動作確認を行うことができました。useCounterは再利用可能な関数なのでどこコンポーネントからでもimportすることで利用することができます。

Composablesな関数

このカウンター機能を自作することでComposablesな関数の作成方法を確認していきます。

VueUseの利用せずApp.vueファイルにカウンター機能を追加するために以下のコードを記述します。ref関数でcountを定義し、inc関数でcountを1増やし、dec関数でcountを1減らせるように関数を設定します。動作確認するとVueUseで利用したuseCounterと同じ動作になります。


<script setup>
import { ref } from 'vue';

const count = ref(0);
const inc = () => (count.value = count.value + 1);
const dec = () => (count.value = count.value - 1);
</script>

<template>
  <h1>VueUse: useCounter</h1>
  <div>Count:{{ count }}</div>
  <div>
    <button @click="inc()">increase</button>
    <button @click="dec()">decrease</button>
  </div>
</template>

上記のコードを利用してcomposablesな関数を作成します。srcフォルダの下にcomposablesフォルダを作成してuseCounter.jsファイルを作成してださい。

useCounter.jsファイルではcount変数とinc, dec関数の設定を行いVueのコンポーネントからimportできるようにexportを行います。この設定によりimportしたコンポーネントでuseCounter関数を実行するとcount, inc, decが戻されます。これでcomposablesな関数の作成は完了です。


import { ref } from 'vue';

export function useCounter() {
  const count = ref(0);
  const inc = () => (count.value = count.value + 1);
  const dec = () => (count.value = count.value - 1);
  return {
    count,
    inc,
    dec,
  };
}

作成したuseCounter.jsファイルをimportして動作確認を行いましょう。VueUseを利用した場合と設定方法と関数名は同じですがimportする場所が異なるので注意してください。今回はVueUseとは異なり先ほど作成したcomposablesフォルダのuseCounter.jsファイルです。


<script setup>
import { useCounter } from './composables/useCounter';
const { count, inc, dec } = useCounter();
</script>

<template>
  <h1>VueUse: useCounter</h1>
  <div>Count:{{ count }}</div>
  <div>
    <button @click="inc()">increase</button>
    <button @click="dec()">decrease</button>
  </div>
</template>

increaseボタンをクリックするとCountの数が増え、decreaseボタンをクリックするとCountの数が減ります。

useCounterを利用したカウント
useCounterを利用したカウント

シンプルな関数ですが自作のcomposablesな関数の作成方法を理解することができました。

VueUseのuseCounterのソースコードを確認して作成方法に違いがないか確認しておきましょう。ソースコードはTypeScriptで記述されているので異なるように見えるかもしれませんが読んでみると先ほど自作した内容と作り方は同じであることがわかります。


import { ref } from 'vue-demi'

export interface UseCounterOptions {
  min?: number
  max?: number
}

/**
 * Basic counter with utility functions.
 *
 * @see https://vueuse.org/useCounter
 * @param [initialValue=0]
 * @param {Object} options
 */
export function useCounter(initialValue = 0, options: UseCounterOptions = {}) {
  const count = ref(initialValue)

  const {
    max = Infinity,
    min = -Infinity,
  } = options

  const inc = (delta = 1) => count.value = Math.min(max, count.value + delta)
  const dec = (delta = 1) => count.value = Math.max(min, count.value - delta)
  const get = () => count.value
  const set = (val: number) => (count.value = val)
  const reset = (val = initialValue) => {
    initialValue = val
    return set(val)
  }

  return { count, inc, dec, get, set, reset }
}

気になる違いとしてはVue2/Vue3でも対応できるように先頭ではref関数をvueではなくvue-demiを使ってimportしています。

Composablesなコンポーネント

VueUseで利用できる関数の中で一部のものは関数だけではなくrenderlessなコンポーネントバージョンを提供しています。これを参考にuseCounter関数をコンポーネント化してみましょう。renderlessはtemplateタグを持たないコンポーネントです。

composablesの関数を利用した場合はcomposablesの関数からimportしているコンポーネントに対してreactiveなデータと関数を渡しました。コンポーネントの場合もcomposablesなコンポーネントから親コンポーネントにreactiveなデータと関数を渡す必要があります。composablesなコンポーネントでは子コンポーネントから親コンポーネントにデータを渡したい時に使う”Scoped Slots”を利用します。

Scoped Slotsがわからない人は公開済みの下記の文書が参考になります。

srcのcomponentsフォルダにUseCounter.vueファイルを作成し以下のコードを記述します。setup関数では引数にpropsとcontextが入っているのでcontextに含まれるslotsを利用します。slotsのdefaultの引数に渡したいデータと関数を設定しています。変数の定義や関数の設定は先ほどの関数の場合と変わりません。


<script>
import { ref } from "vue";

export default {
  setup(props, context) {
    const count = ref(0);
    const inc = () => (count.value = count.value + 1);
    const dec = () => (count.value = count.value - 1);

    return () =>
      context.slots.default({
        count,
        inc,
        dec,
      });
  },
};
</script>

分割代入を利用してcontextからslotsのみ取り出して利用することも可能です。


<script>
import { ref } from "vue";

export default {
  setup(props, { slots }) {
    const count = ref(0);
    const inc = () => (count.value = count.value + 1);
    const dec = () => (count.value = count.value - 1);

    return () =>
      slots.default({
        count,
        inc,
        dec,
      });
  },
};
</script>

App.vueファイル側ではScoped Slotを利用してv-slot:defaultでUseConterコンポーネントからデータを受け取ることができます。slotPropsの中にcount, inc, decが含まれているのでそれを利用します。


<script setup>
import UseCounter from './components/UseCounter.vue';
</script>

<template>
  <h1>VueUse: useCount</h1>
  <use-counter v-slot:default="slotProps">
    <div>Count:{{ slotProps.count }}</div>
    <div>
      <button @click="slotProps.inc()">increase</button>
      <button @click="slotProps.dec()">decrease</button>
    </div>
  </use-counter>
</template>

slotPropsを分割代入して変数と関数を取り出すことができこちらのほうがコードがすっきりします。


<script setup>
import UseCounter from './components/UseCounter.vue';
</script>

<template>
  <h1>VueUse: useCount</h1>
  <use-counter v-slot:default="{ count, inc, dec }">
    <div>Count:{{ count }}</div>
    <div>
      <button @click="inc()">increase</button>
      <button @click="dec()">decrease</button>
    </div>
  </use-counter>
</template>

これで設定は完了です。useCounterの関数を利用した場合と動作は変わりません。

useCounterを利用したカウント
UseCounterコンポーネントを利用したカウント

カウンター機能というシンプルなコードを利用してComposablesな関数、コンポーネントを作成することができました。特にコンポーネントについてはScoped Slotsを利用するため最初は戸惑ってしまう人もいるかもしれませんがどのように値を渡し、受け取るかがわかってしまえば関数とそれほど作成の難しさに差はないかと思います。

Composition APIではComposablesな関数を利用して再利用な関数を簡単に利用できることが特徴です。VueUseに存在しない関数が必要な場合はぜひComposablesな関数を自作して効率的な開発に役立ててください。