🥳

Vue.js は Reactivity Transform でさらに進化する

2022/02/14に公開

Reactivity Transform とは

Vue 3.2.25 から experimental で実装されている機能です[1]。script setup の defineProps() などと同様、コンパイラーマクロによってコードを変換する仕組みです。

公式ドキュメントからコードを引用しつつ、主要なポイントを解説したいと思います[2]

ref の変換

今まで Composition API の ref の値を使用するには毎回 .value を書く必要がありました。Reactivity Transform の $ref() を使用すると以下のように .value なしで値にアクセスしたり再代入できるようになります。

<script setup>
let count = $ref(0)

console.log(count)

function increment() {
  count++
}
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>

とてもシンプルで分かりやすいですね。
このコードはコンパイル時に次のように変換されます。

import { ref } from 'vue'

let count = ref(0)

console.log(count.value)

function increment() {
  count.value++
}

$ref 以外に $computed$shallowRef なども用意されています。

分割代入

ref のオブジェクトを返すコンポーザブル関数などには、$() を使用すると分割代入した結果に .value なしでアクセスできます。

import { useMouse } from '@vueuse/core'

const { x, y } = $(useMouse())

console.log(x, y)

このコードはコンパイル時に次のように変換されます。

import { toRef } from 'vue'
import { useMouse } from '@vueuse/core'

const __temp = useMouse(),
  x = toRef(__temp, 'x'),
  y = toRef(__temp, 'y')

console.log(x.value, y.value)

ref に戻す

.value なしでアクセスできるのは便利ですが、ref として扱いたい場合もあります。

function trackChange(x: Ref<number>) {
  watch(x, (x) => {
    console.log('x changed!')
  })
}

let count = $ref(0)
trackChange(count) // doesn't work!

このコードの trackChangeRef<number> を引数にとりますが、以下のようにコンパイルされるのでうまく動きません。

let count = ref(0)
trackChange(count.value)

この場合は count 変数を $$() でラップすることで、コンパイル後も ref のままになります。

let count = $ref(0)
- trackChange(count)
+ trackChange($$(count))

let count = ref(0)
trackChange(count)

TypeScript で使う

型定義ファイルに以下を追加することで、マクロの型情報がグローバルに登録され、型推論やコード補完などが有効になります。

/// <reference types="vue/macros-global" />

オプトイン手順

2022 年 2 月現在、Reactivity Transform はデフォルトでは無効になっているので、有効化するための設定が必要となります。
また、vue@^3.2.25 が必要です。

Vite

@vitejs/plugin-vue@^2.0.0 が必要。

// vite.config.js
export default {
  plugins: [
    vue({
      reactivityTransform: true
    })
  ]
}

公式ドキュメントには vue-cliwebpack + vue-loader 向けの設定もあります。

まとめ

script setup に引き続き、Vue.js のコードがどんどんシンプルになっていきますね。.value が消えるとだいぶ読みやすくなって良いと思います。一方で $()$$() は直感的でないと感じる人もいそうなので好みが分かれるところでしょうか。

Evan 氏のコメントによると、Q2 にリリースされる Vue 3.3 にて experimental が取れるようなので、それまでは破壊的変更があるかも知れません。

ここのところ、次から次へと新しい機能が Vue.js に取り入れられているので、今後どんな機能が入っていくのか楽しみですね。

脚注
  1. CHANGELOG を確認したところ、3.2.0 に ref sugar という名前で原形となる機能が入っていたようです。その後 ref transform という名称を経て、3.2.25 で reactivity transform になり大幅に機能拡充されて今の形になりました。 ↩︎

  2. だいぶ端折ってあるので、詳しく知りたい方は公式ドキュメントを参照してください。 ↩︎

Discussion