This page looks best with JavaScript enabled

【Vue.js】v-ifと$refsによるTypeErrorの対処法

 ·   ·  ☕ 2 分で読めます
✏️

v-ifを設定したコンポーネントに対してthis.$refsで要素を取得しようとするとunderfinedになります。

以下、具体例と対処法です。
開発環境はVue.js 2.6.11です。

コード

例は適当です。最低限の部分しか書いていません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<template>
  <div>
    <!-- 編集部分 -->
    <status-edit v-if="isEditing" ref="editArea" />
    <!-- ビュー部分 -->
    <status-view v-if="!isEditing" />
    <!-- ボタン -->
    <button v-if="!isEditing" @click="pushEdit">編集</button>
  </div>
</template>

<script>
import statusView from "./StatusView";
import statusEdit from "./StatusEdit";

export default {
  components: {
    statusView,
    statusEdit,
  },
  data() {
    return {
      isEditing: false,
    };
  },
  methods: {
    pushEdit() {
      // isEditingをtrueにすることで編集画面/表示画面を切り替える
      this.isEditing = true;
      // statusEditコンポーネントの中のfetchDateメソッドを実行
      this.$refs.editArea.fetchData();
    },
  },
};
</script>

エラー

[Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'fetchData' of undefined"

vue.runtime.esm.js:1927 TypeError: Cannot read property 'fetchData' of undefined

「編集」ボタンを押すと、このようなエラーが出ます。
this.$refs.editAreaがunderfinedになっているから、fetchDataなんてプロパティは読み込めないよ」という意味です。

原因

v-if="false"のとき、statusEditコンポーネントはページ上に存在していません。
そして、メソッド内の処理は非同期に行われます。
つまり、コンポーネントが描画されていない状態でthis.$refs.editAreaを取得しようとするので、当然underfinedになってしまうのです。

解決法

async/awaitを使う

1
2
3
4
5
6
methods: {
  async pushEdit() {
    await (this.isEditing = true)
    this.$refs.editArea.fetchData()
  }
}

async/awaitでコンポーネントが描画されるのを待ちます。その後、$refsでコンポーネントを取得してメソッドを実行します。

v-ifをv-showに変える

1
<status-edit v-show="isEditing" ref="editArea" />

v-showdisplay: none;によって見えていないだけで描画はされているので、コンポーネント内のメソッドを実行することができます。

参考リンク

Share on

END
END
@aiandrox

目次