thumbnail

【Vue3】script setup構文の使用方法とメリット【propsとemitsも解説】

Vue3.2で<script setup>構文が導入され、Composition APIの記述が簡単になりました。<script setup>構文は記述が簡単になるだけでなく、他にも多くのメリットが存在します。この記事では<script setup>構文の説明から、propsやemitなどの特有の記述方法、メリットなどを説明します。

<script setup>構文の基本

記述方法

<script setup>構文は、従来のComposition APIのシンタックスシュガー(中身は同じで別の書き方)です。

Composition APIをご存じない方はこちらの記事を参照下さい。

<script setup>構文ですが、使うために必要なのはscriptタグ内ににsetupと記述するだけです。
まずは従来の記述方法と比較することで、具体的な記述方法を見ていきます。

・<script setup>構文

<script lang="ts" setup>
import { computed, ref } from 'vue'
//変数
const hoge = ref("hoge")
const num = ref<number>()
//関数
const onClick = () => console.log("clicked!")
//computed
const twice = computed(() => num.value)
</script>

従来の方法

同じ内容のコードを従来通りに書くと次のようになります。

<script lang="ts">
import { defineComponent, ref, computed } from "vue";
export default defineComponent({
  setup() {
    //変数
    const hoge = ref("hoge")
    const num = ref<number>()
    //関数
    const onClick = () => console.log("clicked!")
    //computed
    const twice = computed(() => num.value)
    return {
      hoge, num, onClick, twice
    }
  }
})
</script>

見ての通り、最初に記載した<script setup>構文では圧倒的に記述が楽になりました。
また、全てトップレベルに記述できるのでコードの見通しも良いです。

具体的に言うと、次の3つの記述が不要になります。

  • export default defineComponentによるオブジェクトのラップ
  • setup()関数
  • return文

トップレベルに書いた変数や関数はがそのままtemplateで使えるのです。

メリット

記述が楽になりコードの見通しが良くなる、以外にも多くのメリットが存在します。
いくつか紹介します。

  • TypeScriptによる型推論のパフォーマンス向上!
  • PropとEmitの記述が楽に!TypeScriptで書ける(後述)
  • templateで使うコンポーネントは、importするだけで使用可能になる!(後述)
  • 実行パフォーマンスの向上!

<script setup>構文でのPropとEmitsの記述方法

基本〜definePropsとdefineEmits〜

従来のComposition APIでPropsとEmitは、setup()と同じ階層に併記していました。

<script setup>構文では、definePropsやdefineEmitsを用いて、トップレベルに記述します。

<script setup lang="ts">
const props = defineProps({
  num: {
    type: Number,
    required: true
  },
  str: {
    type: String,
    default: "hoge"
  }
})
const emits = defineEmits(
  ['change']
)
</script>

typeやrequired、defaultの書き方は普通のsetup文の時と変わりません。

TypeScriptによる簡略化した記述

TypeScriptのジェネリックを使えば、更に簡単に記述できます。

<script setup lang="ts">
const props = defineProps<{
  num: number,
  str?: string //?なのでrequired: falseと同じ
}>()
const emits = defineEmits<{
  (e: 'change', id: number): void
}>()
</script>

以下、このコードについて解説します。

definePropsについて補足

コード例に載せたとおり、propsの型はTypeScriptの記述で指定します。
「num: number」はnumber型で必須(required: true)のpropsを表し、
「str?: string」はstring型で任意(required: false)のpropsにできます。

このように?の有無でrequiredの指定ができます。

ただし、この記述方法ではpropsのデフォルト値が表現できません。
デフォルト値が必要な場合はwithDefaults関数を利用します。

const props = withDefaults(defineProps<{
  num?: number,
  str?: string
}>(), {
  num: 3,
  str: "hoge"
})

また、scriptブロック内でpropsは利用せずにtemplateブロック内でのみ利用する場合、const propsに代入せずに次のような宣言をするだけで構いません。

defineProps<{ msg: string }>()

defineEmitsについて補足

ジェネリックの<>内で必要な数のemitを定義していきます。
基本的な書き方は次のとおりです。

const emits = defineEmits<{
  (e: "Emitの名前", 渡したい引数: 型): void
  (e: "Emitの名前2", 渡したい引数: 型): void
}>()

具体的な使用例を載せます。

<script setup lang="ts">

const emits = defineEmits<{
  (e: "hoge", num: number): void
  (e: "fuga"): void
}>()

const onclick = () => {
  emits("hoge", 3) //3を引数にhogeを発火
  emits("fuga") //引数無しでfugaを発火
}

</script>

コンポーネントは、importするだけで使用可能になる

templateで使うコンポーネントは、script setupブロック内でimportするだけで、template側で使用可能になります。

<script setup lang="ts">
import Child from './Child.vue';
</script>

<template>
  <Child /> 
</template>

その他のトピック

親コンポーネントに変数を公開するには

親がテンプレート参照を用いて子トップレベルの変数等にアクセスするには、defineExposeを使う必要があります。

const num = ref<number>()
defineExpose({
  num
})

これで、このコンポーネントを利用する親コンポーネントはテンプレート参照を用いてnumにアクセスできます。

exportするには

<script setup>構文ではexportの記述ができません。
従来の<script>だけの構文も記述してexportする必要があります。

<script lang="ts">
export const hoge = "fuga" //OK
</script>

<script setup lang="ts">
// export const fuga = "fuga" //エラー
</script>

まとめ

<script setup>構文について、一通りの使い方とメリットを紹介しました。非常に多くのメリットが存在し、記述が簡単になり開発効率も上がるので積極的に利用すべきです。