Vue.js 3とは?React・Angularとの違い
Vue.js 3は2020年9月にリリースされた、プログレッシブなJavaScriptフレームワークです。学習曲線が緩やかでありながら、大規模アプリケーション開発にも対応できる柔軟性が特徴です。Vue 3ではComposition APIの導入により、ロジックの再利用性と TypeScriptとの親和性が大幅に向上しました。
| 特徴 | Vue.js 3 | React 18 | Angular 17 |
|---|---|---|---|
| 学習難易度 | 低〜中 | 中 | 高 |
| パフォーマンス | 高速 | 高速 | 良好 |
| TypeScript対応 | ◎(組み込み) | ○(追加設定) | ◎(標準) |
| 公式SSR | Nuxt 3 | Next.js | Angular Universal |
| 状態管理 | Pinia | Redux/Zustand | NgRx |
Vue.js 3環境構築
# create-vue(Viteベース)でプロジェクト作成
npm create vue@latest my-vue-app
# オプション選択例
# ✔ Add TypeScript? › Yes
# ✔ Add JSX Support? › No
# ✔ Add Vue Router? › Yes
# ✔ Add Pinia? › Yes
# ✔ Add Vitest? › Yes
# ✔ Add ESLint? › Yes
cd my-vue-app
npm install
npm run dev
Composition APIの基本
setup()とref・reactive
<script setup lang="ts">
import { ref, reactive, computed, watch, onMounted } from 'vue'
// ref: プリミティブ値のリアクティブ化
const count = ref(0)
const message = ref('Hello Vue 3!')
// reactive: オブジェクトのリアクティブ化
const user = reactive({
name: '田中太郎',
age: 30,
email: 'taro@example.com'
})
// computed: 算出プロパティ
const doubleCount = computed(() => count.value * 2)
const fullProfile = computed(() => `${user.name}(${user.age}歳)`)
// watch: 値の変化を監視
watch(count, (newVal, oldVal) => {
console.log(`count changed: ${oldVal} → ${newVal}`)
})
// ライフサイクルフック
onMounted(() => {
console.log('コンポーネントがマウントされました')
})
// メソッド
const increment = () => count.value++
const reset = () => { count.value = 0 }
</script>
<template>
<div class="counter">
<h1>{{ message }}</h1>
<p>カウント: {{ count }} (2倍: {{ doubleCount }})</p>
<button @click="increment">+1</button>
<button @click="reset">リセット</button>
<p>{{ fullProfile }}</p>
</div>
</template>
コンポーザブル(Composables)でロジックを再利用
Composition APIの真価はコンポーザブル(Composables)によるロジックの再利用です。
// composables/useCounter.ts
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0, step = 1) {
const count = ref(initialValue)
const doubleCount = computed(() => count.value * 2)
const isPositive = computed(() => count.value > 0)
const increment = () => (count.value += step)
const decrement = () => (count.value -= step)
const reset = () => (count.value = initialValue)
return {
count,
doubleCount,
isPositive,
increment,
decrement,
reset
}
}
// composables/useFetch.ts
import { ref, onMounted } from 'vue'
export function useFetch<T>(url: string) {
const data = ref<T | null>(null)
const loading = ref(true)
const error = ref<Error | null>(null)
const fetchData = async () => {
loading.value = true
try {
const res = await fetch(url)
data.value = await res.json()
} catch (e) {
error.value = e as Error
} finally {
loading.value = false
}
}
onMounted(fetchData)
return { data, loading, error, refetch: fetchData }
}
Vue RouterとPiniaの実装
// stores/userStore.ts(Pinia)
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
interface User {
id: number
name: string
email: string
role: 'admin' | 'user'
}
export const useUserStore = defineStore('user', () => {
const currentUser = ref<User | null>(null)
const isLoading = ref(false)
// Getters
const isLoggedIn = computed(() => currentUser.value !== null)
const isAdmin = computed(() => currentUser.value?.role === 'admin')
// Actions
const login = async (email: string, password: string) => {
isLoading.value = true
try {
// APIコール
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email, password })
})
currentUser.value = await res.json()
} finally {
isLoading.value = false
}
}
const logout = () => {
currentUser.value = null
}
return { currentUser, isLoading, isLoggedIn, isAdmin, login, logout }
})
Nuxt 3でSSR・SSG対応
本番環境でのSEO対策やパフォーマンス向上にはNuxt 3を使います。
# Nuxt 3プロジェクト作成
npx nuxi@latest init my-nuxt-app
cd my-nuxt-app
npm install
npm run dev
# ディレクトリ構造
# pages/ → ファイルベースルーティング
# components/ → Vueコンポーネント
# composables/ → 共有ロジック
# server/api/ → APIルート
# public/ → 静的ファイル
<!-- pages/blog/[slug].vue -->
<script setup lang="ts">
const route = useRoute()
const slug = route.params.slug as string
// データフェッチング(SSR対応)
const { data: post, pending, error } = await useFetch(`/api/posts/${slug}`)
// SEOメタタグ
useHead({
title: post.value?.title,
meta: [
{ name: 'description', content: post.value?.excerpt },
{ property: 'og:title', content: post.value?.title },
{ property: 'og:description', content: post.value?.excerpt },
{ property: 'og:image', content: post.value?.thumbnail }
]
})
</script>
<template>
<article v-if="post">
<h1>{{ post.title }}</h1>
<div v-html="post.content"></div>
</article>
<div v-else-if="pending">読み込み中...</div>
<div v-else-if="error">エラーが発生しました</div>
</template>
パフォーマンス最適化
<script setup>
import { defineAsyncComponent, shallowRef } from 'vue'
// 遅延ロード(コード分割)
const HeavyComponent = defineAsyncComponent(() =>
import('./HeavyComponent.vue')
)
// v-memo: リストのメモ化
// v-once: 一度だけレンダリング
</script>
<template>
<!-- 遅延ロードコンポーネント -->
<Suspense>
<HeavyComponent />
<template #fallback>読み込み中...</template>
</Suspense>
<!-- 大量リストのメモ化 -->
<div v-for="item in list" :key="item.id" v-memo="[item.selected]">
{{ item.name }}
</div>
</template>
まとめ
Vue.js 3はComposition API・TypeScript対応・Pinia状態管理・Nuxt 3によるSSRと、モダンなWeb開発に必要な要素が揃っています。Reactと比べて学習曲線が緩やかで、特に日本語のコミュニティとドキュメントが充実しているため、日本のエンジニアには非常に学びやすい選択肢です。フロントエンドスキルのアップグレードにぜひVue.js 3をお試しください。