Vue Composition API によって Vue.js にも React Hooks のようなロジックの再利用性の高い開発体験がもたらされようとしています。
しかし、まだ「Composition API の良さをわかっていない」という方や「Composition API をうまく利用した書き方がわからない」という方も多いかと思います。
本記事では Composition API 時代の便利ライブラリ VueUse を用いた実装例や、 VueUse 自体の実装がどのようなものか紹介します。
Composition API の良さや雰囲気もキャッチアップしていただければ幸いです。
VueUse とは?
VueUse は Anthony Fu さん1が中心に開発しているライブラリで、Composition API を用いた便利系関数を数多く集めたライブラリです。
例えば、ブラウザ上のマウスポインタの座標をリアクティブに取得する useMouse()
, ブラウザ API の localStorage を使って状態を保持できる useLocalStorage()
, 負荷対策のために連続する関数呼び出しを防ぐ useDebounceFn()
2などといった関数が提供されています。
公式サイト: https://vueuse.org/
GitHub: vueuse/vueuse
npm: @vueuse/core
検証環境の構築
GitHub リポジトリの Description に記載通り、Vue 2系・3系のどちらでも利用可能です:
🧰 Collection of Composition API utils for Vue 2 and 3 https://vueuse.js.org/
今回は Vue CLI で立ち上げた Vue 2.6 系のプロジェクトに @vue/composition-api をプラグインとして追加した環境で検証します。
動作確認した環境
- macOS Catalina
- Chrome 83
- Node.js 12.18.1
- npm 6.14.5
- Vue CLI v4.4.4
-
vue
2.6.11
-
-
@vue/composition-api
0.6.5 -
@vueuse/core
2.0.34
Vue CLI のインストール
npm i -g @vue/cli
Vue CLI をグローバルインストールしたくない方は、以下の手順の vue
コマンド部分を npx @vue/cli
に読み替えていただいても大丈夫です。
プロジェクトの作成
vue-2-vueuse-trial
というプロジェクト名で環境を構築していきます:
vue create vue-2-vueuse-trial
設定は以下のようにしました:
Vue CLI v4.4.4
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Linter
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? No
? Pick a linter / formatter config: Basic
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
プラグインと VueUse の導入
プロジェクトディレクトリが出来上がったら、@vue/composition-api と VueUse を npm install
します:
(2023/02/25 追記) Vue 2.7, Vue 3.x の場合は @vue/composition-api
のインストールは不要です
cd vue-2-vueuse-trial
npm i @vueuse/core @vue/composition-api
src/main.ts
に Vue.use(VueCompositionAPI)
を追加します3:
import Vue from 'vue'
+import VueCompositionAPI from '@vue/composition-api'
import App from './App.vue'
+Vue.use(VueCompositionAPI)
Vue.config.productionTip = false
npm run serve
で開発ビルドを開始してください。
VueUse の関数を使ってみる
useMouse()
リアクティブにマウスポインタの座標が取得できる useMouse()
を使ってみます:
<template>
<div>
{{ x }}, {{ y }}
</div>
</template>
<script lang="ts">
import { defineComponent } from '@vue/composition-api'
import { useMouse } from '@vueuse/core'
export default defineComponent({
setup() {
// tracks mouse position
const { x, y } = useMouse()
return { x, y }
}
})
</script>
これだけでマウスポインタの座標がリアクティブに反映されていることがわかるかと思います。
useMouse()
の実装を確認すると useEventListener()
という関数を使っていて、 useEventListener()
はコンポーネントのマウント時(Composition API の onMounted()
を利用)にイベントリスナーを追加していることがわかります:
https://github.com/antfu/vueuse/blob/master/packages/core/useMouse/index.ts
https://github.com/antfu/vueuse/blob/master/packages/core/useEventListener/index.ts
VueUse ではこのような関数がより抽象的な関数を参照しているパターンの実装が所々に見られます。
Composition API を用いた良い実装の例として知っておくと良いかと思います。
useLocalStorage()
ブラウザ API の localStorage を使って状態を保持できる useLocalStorage()
を使ってみます。
まずは useLocalStorage()
を使わず、 VueUse がなくても利用できる reactive()
4 を使ってみましょう:
<template>
<div>
<div>
name: <input v-model="state.name" />
</div>
<div>
color: <input v-model="state.color" />
</div>
<div>{{ state }}</div>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive } from '@vue/composition-api'
export default defineComponent({
setup() {
const state = reactive({
name: 'Apple',
color: 'red',
})
return { state }
}
})
</script>
name, color を変更すると、下に表示されている JSON 形式の state
の表示も更新される画面が表示されます:
上記の実装では name を Banana, color を yellow のように変更してページをリロードすると、元の状態(name が Apple, color が red)に戻ります。
以下のように <script lang="ts">
ブロックを変更し、reactive()
の代わりに useLocalStorage()
を利用するように変更してみます:
import { defineComponent } from '@vue/composition-api'
import { useLocalStorage } from '@vueuse/core'
export default defineComponent({
setup() {
// persist state in localStorage
const state = useLocalStorage(
'my-storage',
{
name: 'Apple',
color: 'red',
},
)
return { state }
}
})
state
が localStorage に保存されるようになったので、ページをリロードしても状態が保持されるようになりました。
サンプルアプリとしてよくある ToDo リストの状態管理に useLocalStorage()
を使うようにすると、手軽にデータを保存できる ToDo リストにできて楽しいかもしれません。
公式サイトが Storybook でできている件
(2023/02/25 追記) 現在は Vitepress が利用されています
https://github.com/vueuse/vueuse/pull/277
公式サイトが Storybook でできていて、各関数を即座に試せるリファレンスとなっています。
各関数のページ下部には関数の "Source" へのリンクがあり、ソースを見てどのような実装になっているか追っていくと Composition API を用いた良い実装の勉強となるかと思います。
所感
VueUse は多くの便利関数を提供しているので、今後お世話になる可能性が高いライブラリだと思いました。
まだ試せていない関数が多くあるので、使ってみたりコードを読んだりしてみようかと思います。
-
@vue/composition-api (Vue 2系用プラグイン)のメンテナーでもあります ↩
-
useDebounceFn()
は Composition API に依存しない純粋な JS の関数となっています。似た名前の関数であるuseDebounce()
は Composition API とuseDebounceFn()
に依存していることに気をつけてコードを読んでみると良いかと思います ↩ -
VueUse の名称は関数名のプレフィックスとして
use
を付ける慣習に由来する物であり、Vue.use()
との関連性はないと思います。なお、Vue 3系からはVue.use()
は App インスタンスに対するオプションに変更される予定(rfc: 0009-global-api-change.md)のため、発話上 VueUse とVue.use()
を区別できない問題は将来的には解消されると思います ↩ -
Vue 2系では
import { reactive } from '@vue/composition-api'
によるreactive
はVue.observable
相当となります。 Vue 3系ではimport { reactive } from 'vue'
のようにして import します ↩