【Vue 3】script setupで書く理由|Options APIとの違いと書き方

プログラミング

※ 当ブログ「日々是事始め(コレコト)」はプロモーションを含みます。

Vue 3 を調べ始めると、同じ「カウンター」のサンプルでも書き方が2種類出てきて戸惑いました。export default { data() {...} } と書くもの(Options API)と、<script setup> と書くものです。結論から言うと、これから学ぶなら <script setup> を標準にしてよいです。この記事では、なぜそう言えるのかを、自分が納得できた順番で整理しました。

※ 学習用に調べた内容を個人的にわかりやすくまとめたものです。文章は AI の補助を受けて作成しています。


3つの書き方の関係を整理する

最初に混乱しがちなので、用語の関係をはっきりさせます。

用語正体
Options APIdata / methods / computed などの「枠」に分けて書く従来スタイル
Composition APIref / computed などの関数で状態を組み立てる書き方(Vue 3で追加)
<script setup>Composition API を最小の記述で書くための構文糖(シンタックスシュガー)

つまり <script setup> は、Composition API を「もっと短く・読みやすく」書くための入れ物です。Options API と Composition API は対立する2択ですが、<script setup> はその上に乗る書き方、という関係です。


同じカウンターを3通りで見比べる

まず Options API。

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  data() {
    return { count: 0 }
  },
  methods: {
    increment() {
      this.count++
    },
  },
})
</script>

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

次に Composition API(setup() 関数を明示的に書く形)。

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    const count = ref(0)
    const increment = () => count.value++
    return { count, increment }
  },
})
</script>

最後に <script setup>setup()returndefineComponent も要りません。

<script setup lang="ts">
import { ref } from 'vue'

const count = ref(0)
const increment = () => count.value++
</script>

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

トップレベルで宣言した countincrement が、そのまま template から使えます。最初に見たとき「return を書かないのに、なぜ template から見えるの?」と引っかかりましたが、これは <script setup> がコンパイル時に自動で公開してくれているためです。


script setup を標準にしてよい理由

  • 記述が減るreturn 漏れで「template に出てこない」事故が起きません。
  • TypeScript と相性が良いdefineProps<T>() のように型から props を定義でき、型推論が効きます。
  • import がそのまま使える:読み込んだ子コンポーネントや関数を、components 登録なしに template で使えます。
  • 公式が推奨:Vue 公式ドキュメントでも SFC では <script setup> が推奨スタイルとして案内されています。

props と emits は define系マクロで書く

<script setup> では、props と emits を defineProps / defineEmits という「コンパイラマクロ」で宣言します(import 不要で使えます)。

<script setup lang="ts">
const props = defineProps<{
  label: string
  disabled?: boolean
}>()

const emit = defineEmits<{
  click: []
}>()
</script>

<template>
  <button :disabled="props.disabled" @click="emit('click')">
    {{ props.label }}
  </button>
</template>

型引数で渡すだけで props の型が決まるのが、Options API には無かった気持ちよさです。props・emits・slots の使い分けは別記事で詳しく扱います。


よくある引っかかり

  • ref.value を script 内で忘れる:template では自動で開かれますが、script 内では count.value と書く必要があります。
  • this は使えない<script setup> には this がありません。Options API の this.xxx の癖が残ると詰まります。
  • マクロは import しないdefineProps などはコンパイラが処理するため、import すると逆に警告になります。


もっと体系的に学ぶなら(書籍)

この記事はシリーズの一部です。TypeScript前提で Composition API・Pinia・Vue Router・テストまで一冊で体系的に学びたい方には、内容がそのまま重なる次の本がおすすめです。

次に読む

【Vue 3入門】リアクティブの基礎を徹底解説!ref・reactive・computed・watchの使い方
Vue.js リアクティブの基礎を徹底解説リアクティブの基礎、ある意味でここが本丸だと思います。Vue.jsの核となる仕組みが リアクティブシステム です。リアクティブを理解すれば、Vueが「なぜ直感的に使えるのか」が腑に落ち、実務での活用...
Vue 3を体系的に学ぶロードマップ|初心者がリアクティブ・REST API・Swagger連携・Vuetifyまで理解する手順
※ 当ブログ「日々是事始め(コレコト)」はプロモーションを含みます。Vue 3 を学び始めたとき、私がいちばん困ったのは「何から手をつければいいのか分からない」ことでした。リアクティブ、Composition API、Vue Router、...

PR

Back to top
タイトルとURLをコピーしました