🚀

ついにβ版となったVue 3.5の魅力的な新機能をまとめてみた

2024/08/14に公開

Vue 3.5 β版のリリースが始まっています!本記事では3.5で追加された新機能などを一足早く動作させてみましたので、個人的に楽しみにしている機能をまとめてみました。

composable

useTemplateRef

テンプレート参照をcomposableとして便利に利用できる関数です。

Vue 3.5より前は以下の様に変数を定義してテンプレート参照を行っていたため、下記のonMountedの処理をcomposableとしてまとめようとしてもテンプレート参照の変数(下記で言えばtemplateRef)自体を渡さなければならず、少し扱いづらいところがありました。

<script setup>
import { ref, onMounted } from 'vue'

const templateRef = ref()

onMounted(() => {
  templateRef.value.innerText = 'hoge'
})
</script>

<template>
  <div ref="templateRef" />
</template>

useTemplateRefを利用すれば先ほどのmount時にinnerTextを変更する処理をcomposable内で完結させることが出来ます。

import { useTemplateRef, onMounted } from 'vue'

export function useSampleTemplateRef(key) {
  const templateRef = useTemplateRef(key)
  
  onMounted(() => {
    templateRef.value.innerText = 'hoge'
  })
}

vueファイルは以下の様になります。だいぶスッキリしました。テンプレート参照の変数自体、リアクティブなデータの様に見える部分もあったため、とても良い変更だと思います。

<script setup>
import { useSampleTemplateRef } from './composables'

useSampleTemplateRef('templateRef')
</script>

<template>
  <div ref="templateRef" />
</template>

ちなみにTypeScriptの場合は型を付けることも可能です。

// ReadOnly<ShallowRef<HTMLElement | null>>
const templateRef = useTemplateRef<HTMLElement>(key)

useId

ReactのuseIdと同様にフォームの属性などに利用可能な一意のIDを生成する関数です(IDはv:0のような形式)。
クライアント-サーバ間で一意のIDとなるため、ハイドレーションの際に不一致が発生することなく安定したIDになります。

<script setup>
import { useId } from 'vue'

const id = useId();
</script>

<template>
  <label :for="id">label</label>
  <input :id="id" />
</template>

Component

deferred Teleport

Teleportにdeferプロパティが追加されました。deferがついたTeleportは他の同じ更新サイクル内の全DOMコンテンツがレンダリングされるまで待機した後にmountを行います。

以下のサンプルコードはEvan氏のPRに記載があった例を少しいじったものです。deferプロパティがない場合には#targetのDOMはレンダリングされていないため失敗しますが、deferによりtargetのDOMがレンダリングされた後にmountされるため正常に動作します。

<template>
  <Teleport defer to="#target">teleport!</Teleport>
  <div id="target"></div>
</template>

Evan氏は当該のPR中でSuspense内での利用についても言及しています。以前はSuspense内でTeleportを利用すると外部の既にレンダリングされたDOMしか対象に出来ませんでしたが、下記の様な使い方も可能になります。

<Suspense>
  <div>
    <AsyncComp />
    <Teleport defer to="#target">...</Teleport>
    <div id="target"></div>
  </div>
</Suspense>

その他Vue全体

reactive props destructureがデフォルトになる

以前より実験的機能となっていましたが、以下の様なdefinePropsの定義した場合でもリアクティブ性を維持することが可能となりました。

import { watchEffect } from 'vue';
const { msg } = defineProps(['msg']);

watchEffect(() => {
  console.log(msg);
});

利用したくない場合はviteの場合以下のオプションで変更可能です。(以前はscript.propsDestructureでした)

export default defineConfig({
  plugins: [
    vue({
      features: {
        propsDestructure: false
      }
    })],
})

watchやwatchEffectなどでpause/resumeが可能となる

下記の様にpauseresumeで処理を一時停止、再開させることが出来ます。

<script setup>
import { ref, watch } from 'vue'

const input = ref('')

const { pause, resume } = watch(input, (val) => {
  console.log(val)
})
</script>

<template>
  <input v-model="input" />
  <button @click="pause()">pause!</button>
  <button @click="resume()">resume!</button>
</template>

その他の機能改善

  • 配列の追跡を最適化してパフォーマンス・メモリ使用量改善
  • custom-elementのヘルパー関数をはじめとした様々な改善
  • TypeScriptの型改善
  • SSR/hydration関連の改善
  • watchdeepを数値で調整可能
  • app.onUnmountなどいくつかの関数追加
  • などなど(まだまだ様々な改善があります!)・・・

所感

軽い気持ちでVue 3.5の新機能を体験しようと思いましたが、書ききれないくらいのボリュームで安定版のリリースが楽しみです。Evan氏をはじめ、全てのVueコントリビューターに感謝をしつつ終わりとさせていただきます。

参照

Vue・Nuxt 情報が集まる広場 / Plaza for Vue・Nuxt.

Discussion