※ 当ブログ「日々是事始め(コレコト)」はプロモーションを含みます。
Vue 3 を調べ始めると、同じ「カウンター」のサンプルでも書き方が2種類出てきて戸惑いました。export default { data() {...} } と書くもの(Options API)と、<script setup> と書くものです。結論から言うと、これから学ぶなら <script setup> を標準にしてよいです。この記事では、なぜそう言えるのかを、自分が納得できた順番で整理しました。
※ 学習用に調べた内容を個人的にわかりやすくまとめたものです。文章は AI の補助を受けて作成しています。
3つの書き方の関係を整理する
最初に混乱しがちなので、用語の関係をはっきりさせます。
| 用語 | 正体 |
|---|---|
| Options API | data / methods / computed などの「枠」に分けて書く従来スタイル |
| Composition API | ref / 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() も return も defineComponent も要りません。
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
トップレベルで宣言した count や increment が、そのまま 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・テストまで一冊で体系的に学びたい方には、内容がそのまま重なる次の本がおすすめです。
PR
📕 紙の本
Vue 3 フロントエンド開発の教科書 [ WINGSプロジェクト 齊藤 新三 ] 価格:3960円 |
📱 電子書籍版
Vue 3 フロントエンド開発の教科書 【電子書籍】[ WINGSプロジェクト 齊藤新三【著】 ] 価格:3960円 |
次に読む




