MeWrite Docs

Vue.js: Cannot read properties of undefined

Vue.jsでdata/computedの初期値がnullの状態でプロパティアクセスした際に発生するTypeError

概要

Vue.jsでTypeError: Cannot read properties of undefinedが発生する主な原因は、datarefの初期値がnullの状態でテンプレート内でプロパティにアクセスすることです。非同期でデータを取得する際に、取得完了前にレンダリングが実行されてエラーになります。

エラーメッセージ

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

発生パターン

Options API

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<template>
  <!-- NG: userがnullの状態でnameにアクセス -->
  <h1>{{ user.name }}</h1>
</template>

<script>
export default {
  data() {
    return {
      user: null  // 初期値がnull
    };
  },
  async mounted() {
    this.user = await fetchUser();
  }
};
</script>

Composition API

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<template>
  <!-- NG: userがnullの状態でnameにアクセス -->
  <h1>{{ user.name }}</h1>
</template>

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

const user = ref(null);  // 初期値がnull

onMounted(async () => {
  user.value = await fetchUser();
});
</script>

解決策

1. v-ifでガード

最も確実な方法。データがある場合のみ描画します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<template>
  <div v-if="user">
    <h1>{{ user.name }}</h1>
  </div>
  <div v-else>
    <p>Loading...</p>
  </div>
</template>

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

const user = ref(null);

onMounted(async () => {
  user.value = await fetchUser();
});
</script>

2. オプショナルチェイニング

テンプレート内でも使用可能です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<template>
  <h1>{{ user?.name ?? 'Loading...' }}</h1>
</template>

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

const user = ref(null);

onMounted(async () => {
  user.value = await fetchUser();
});
</script>

3. 配列は空配列で初期化

v-forを使う場合は初期値を[]にします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<template>
  <ul>
    <li v-for="user in users" :key="user.id">
      {{ user.name }}
    </li>
  </ul>
</template>

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

// OK: 初期値を空配列にする
const users = ref([]);

onMounted(async () => {
  users.value = await fetchUsers();
});
</script>

4. computedでデフォルト値を返す

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<template>
  <h1>{{ userName }}</h1>
</template>

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

const user = ref(null);

const userName = computed(() => {
  return user.value?.name ?? 'Loading...';
});

onMounted(async () => {
  user.value = await fetchUser();
});
</script>

5. propsにdefault値を設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<script setup>
const props = defineProps({
  user: {
    type: Object,
    default: () => ({})  // デフォルト値
  }
});
</script>

<template>
  <h1>{{ user.name ?? 'Unknown' }}</h1>
</template>

6. TypeScriptで型安全にする

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<script setup lang="ts">
import { ref, onMounted } from 'vue';

interface User {
  id: number;
  name: string;
}

const user = ref<User | null>(null);

onMounted(async () => {
  user.value = await fetchUser();
});
</script>

<template>
  <div v-if="user">
    <h1>{{ user.name }}</h1>
  </div>
</template>

Composableで再利用

データ取得パターンを共通化します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// composables/useFetch.js
import { ref } from 'vue';

export function useFetch(url) {
  const data = ref(null);
  const loading = ref(true);
  const error = ref(null);

  fetch(url)
    .then(res => res.json())
    .then(json => data.value = json)
    .catch(err => error.value = err)
    .finally(() => loading.value = false);

  return { data, loading, error };
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<script setup>
import { useFetch } from '@/composables/useFetch';

const { data: user, loading, error } = useFetch('/api/user/1');
</script>

<template>
  <p v-if="loading">Loading...</p>
  <p v-else-if="error">Error: {{ error.message }}</p>
  <h1 v-else>{{ user?.name }}</h1>
</template>

よくある間違い

  • v-ifとv-forの同時使用: 同じ要素にv-ifv-forを使うと予期しない動作になる。<template>でラップする
  • refの.valueを忘れる: <script>内ではuser.value、テンプレート内ではuserでアクセス
  • リアクティブでないオブジェクトのプロパティ追加: Vue 3ではreactiveオブジェクトに新しいプロパティを追加しても自動追跡される

関連エラー

関連エラー

JavaScript の他のエラー

最終更新: 2026-02-03