LoginSignup
16
7

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-05-14

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

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

コード

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

<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を使う

methods: {
  async pushEdit() {
    await (this.isEditing = true)
    this.$refs.editArea.fetchData()
  }
}

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

v-ifをv-showに変える

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

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

参考リンク

16
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
7