11.

Vue.js よくあるエラー集と対処完全ガイド

編集
この記事の要点
  • Failed to mount component — テンプレート構文ミスまたは props 型不一致
  • Cannot read property of undefined — リアクティビティ未確立、v-if でガード or オプショナルチェイニング
  • v-model が動かない — カスタムコンポーネントで modelValue / update:modelValue emit 漏れ
  • Vue 2 → 3 移行: Vue.filter / Vue.prototype / $listeners 廃止
  • Vuex → Pinia 推奨。Vuex 4 は保守モード
  • Nuxt の Hydration mismatch — SSR と CSR のレンダリング差分。<ClientOnly> で囲む

Vue.js でよく遭遇するエラー一覧

Vue 3 を中心に、開発で頻出するエラーと対処をまとめます。多くは Vue 2 にも当てはまります。

1. Failed to mount component

[Vue warn]: Failed to mount component: template or render function not defined.
[Vue warn]: Property "xxx" was accessed during render but is not defined on instance.

原因と対処:

  • SFC で <template> ブロック忘れ → 追加
  • defineComponent 戻り値の template プロパティが未定義 → render または template 追加
  • 動的 import 失敗 → ファイルパス / 拡張子確認
  • Volar / TypeScript 設定で SFC 認識不能 → tsconfig.jsonvueCompilerOptions 確認
<!-- ❌ template ブロック無し -->
<script setup>
const msg = 'hi'
</script>

<!-- ✅ -->
<script setup>
const msg = 'hi'
</script>

<template>
  <div>{{ msg }}</div>
</template>

2. Cannot read properties of undefined (リアクティビティ)

TypeError: Cannot read properties of undefined (reading 'name')

非同期データの初期値が未定義のままレンダリングされた典型例:

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

const user = ref(null)

onMounted(async () => {
  user.value = await fetch('/api/me').then(r => r.json())
})
</script>

<template>
  <!-- ❌ user.name で user が null -->
  <div>{{ user.name }}</div>

  <!-- ✅ パターン1: v-if でガード -->
  <div v-if="user">{{ user.name }}</div>

  <!-- ✅ パターン2: オプショナルチェイニング -->
  <div>{{ user?.name }}</div>

  <!-- ✅ パターン3: 初期値を与える -->
  <!-- script 側: const user = ref({ name: '' }) -->
</template>

3. ref / reactive の誤用

import { ref, reactive } from 'vue'

// ❌ ref を渡されたつもりで生の値を扱う
const count = ref(0)
console.log(count + 1)   // → "[object Object]1"
// ✅
console.log(count.value + 1)

// ❌ reactive オブジェクトを分割代入 → リアクティビティ消失
const state = reactive({ name: 'a' })
const { name } = state              // 普通の文字列
name = 'b'                          // ❌ state.name は変わらず

// ✅ toRefs で個別 ref 化
import { toRefs } from 'vue'
const { name } = toRefs(state)
name.value = 'b'                    // ✅ state.name も更新

// ❌ reactive を再代入
let s = reactive({ a: 1 })
s = { a: 2 }                        // ❌ リアクティビティ切断
// ✅ プロパティを更新
s.a = 2
// または ref + .value で全置換
const sref = ref({ a: 1 })
sref.value = { a: 2 }               // ✅

4. v-model が動かない (カスタムコンポーネント)

Vue 3 の v-model は modelValue + update:modelValue イベント。

<!-- 親 -->
<MyInput v-model="text" />

<!-- ❌ Vue 2 流儀 (動かない) -->
<script>
export default {
  props: ['value'],
  emits: ['input'],
}
</script>

<!-- ✅ Vue 3 -->
<script setup>
defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>

<template>
  <input :value="modelValue"
         @input="emit('update:modelValue', $event.target.value)" />
</template>

<!-- ✅ defineModel (Vue 3.4+, より簡潔) -->
<script setup>
const text = defineModel()
</script>
<template>
  <input v-model="text" />
</template>

5. Vue 2 → 3 移行で消えた API

Vue 2Vue 3 での扱い
Vue.filter('xxx', fn)廃止。computed や methods で代替
Vue.prototype.$xxxapp.config.globalProperties.$xxx
$listeners$attrs に統合
v-on.native不要 (デフォルトでネイティブ)
v-model.syncv-model:xxx + 複数 v-model
new Vue({...})createApp({...}).mount(...)
Functional Component関数で書くだけ (props 引数)
Vue.set / Vue.delete不要 (Proxy ベースリアクティビティ)
EventBus (new Vue())mitt 等の外部ライブラリ推奨

6. Vue Router の動的ルート

// Vue Router 4
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/users/:id', component: UserDetail },
    { path: '/users/:id(\\d+)', component: UserDetail },     // 数値のみ
    { path: '/files/:path(.*)*', component: FileView },      // catch-all
  ],
})

// 動的ルートで同じコンポーネントが再利用される
// → 同じコンポーネントだとライフサイクル発火しない
// 対処: route.params を watch
import { watch } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()
watch(() => route.params.id, async (newId) => {
  await loadUser(newId)
}, { immediate: true })

// or :key で強制再生成
// <router-view :key="$route.fullPath" />

7. Pinia (推奨ストア)

// store/counter.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const double = computed(() => count.value * 2)
  function increment() {
    count.value++
  }
  return { count, double, increment }
})

// コンポーネントから
<script setup>
import { useCounterStore } from '@/store/counter'
import { storeToRefs } from 'pinia'

const store = useCounterStore()
const { count, double } = storeToRefs(store)   // リアクティブ維持
const { increment } = store                    // 関数は分割代入 OK
</script>

8. Production 警告を抑制

// main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// 開発環境のみ警告ハンドラ
app.config.warnHandler = (msg, instance, trace) => {
  if (msg.includes('Component name')) return   // 特定警告を抑制
  console.warn(msg, trace)
}

// 本番では Vue 自体が警告を出さない (vue.runtime.prod.js)
app.mount('#app')

9. Vue DevTools 利用

  • Chrome 拡張 / Firefox アドオン: 「Vue.js devtools」
  • スタンドアロン版: npm i -g @vue/devtoolsvue-devtools 起動
  • コンポーネントツリー / Pinia ストア / イベント / Performance を可視化
  • 本番ビルドでは無効化される。デバッグしたい場合は __VUE_PROD_DEVTOOLS__ = true

10. Nuxt の Hydration mismatch

[Vue warn]: Hydration node mismatch:
- Client vnode: <div>...
- Server rendered DOM: <span>...
Hydration completed but contains mismatches.

原因: SSR と CSR で生成される DOM が異なる (時刻、Math.random、window 参照など)。

<!-- ❌ サーバとクライアントで違う値 -->
<div>{{ new Date().toLocaleString() }}</div>

<!-- ❌ window はサーバに無い -->
<div>{{ window.innerWidth }}</div>

<!-- ✅ ClientOnly で囲む (Nuxt) -->
<ClientOnly>
  <div>{{ new Date().toLocaleString() }}</div>
</ClientOnly>

<!-- ✅ onMounted で window を扱う -->
<script setup>
import { ref, onMounted } from 'vue'
const width = ref(0)
onMounted(() => { width.value = window.innerWidth })
</script>

<!-- ✅ useState / useFetch でサーバ側で確定させてから渡す -->
<script setup>
const { data } = await useFetch('/api/now')   // SSR で確定
</script>

FAQ

Q: watch が発火しない
A: ref なら watch(myRef, ...)、reactive 内プロパティは watch(() => state.x, ...) のように関数で。

Q: コンポーネントが再描画されない
A: リアクティビティ切断 (分割代入、再代入)。toRefsref 化で解決。

Q: provide / inject がアプリ全体で動かない
A: app.provide(key, value) をルートで設定。コンポーネント内 provide はサブツリーのみ有効。

Q: TypeScript で props の型が効かない
A: defineProps<{ id: number }>() でジェネリック指定。または defineProps({ id: { type: Number, required: true } })

編集
Post Share
子ページ
  1. Error in created hook: "ReferenceError: axios is not defined"
同階層のページ
  1. インストール(ファイルのダウンロード)
  2. npmを使用したプロジェクトの作成
  3. for 繰り返し処理
  4. ifの条件分岐とtemplateを用いたグループ化
  5. クリック時のイベント処理(on:click)
  6. modelとdata フォーム入力値とDOMへの即時反映
  7. computed(算出プロパティ)と使い方とdataとの違い
  8. ライフサイクルフック(created / mounted / updated / destroyedの使い方)
  9. $nextTickの使い方(ライフサイクルフック)
  10. メソッドの定義方法
  11. エラー一覧
  12. ルーティング設定
  13. aリンクの貼り方と動的URLの作成
  14. Mixinを利用した共通処理の記述方法
  15. v-bindによるデータ連携
  16. ヘッダー/フッターの共通コンポーネント
  17. ナビゲーションの現在ページをハイライトする方法
  18. 画面サイズの取得方法

最近更新/作成されたページ