10
6

More than 3 years have passed since last update.

v-ifで同一のコンポーネントの表示を切り替えた時にcreatedが発火しない問題とその解決

Last updated at Posted at 2019-11-28

たぶんすごい基礎中の基礎なんだろうけど、結構詰まったので。

どういうことか

例えばこんなコンポーネントがあるとする。
渡したvalueを表示するだけのコンポーネント

TestComponent.vue
<template>
  <div>
    {{ value }}
  </div>
</template>

<script>
export default {
  props: {
    value: { type: String }
  },
  created() {
    console.log("created");
  }
};
</script>

こんな感じで利用する

Main.vue
<template>
  <div>
    <button @click="click">Click</button>
    <div>
      <testComponent value="a" v-if="testOpen"/>
      <testComponent value="b" v-else/>
    </div>
  </div>
</template>

<script>
import testCompoment from "TestComponent"

export default {
  data() {
    return {
      testOpen: false
    }
  },
  components: {
    testComponent
  },
  methods: {
    click() {
      this.testOpen = !this.testOpen;
    }
  }
};
</script>

クリックすると片方のコンポーネントが表示され、もう片方が消え、画面表示のa,bが切り替わる画面

予測していた動作

クリックをするたびにcreatedが呼ばれ、画面表示のa,bが切り替わる。

実際の動作

createdが最初しか呼ばれない。

See the Pen wvvVJXj by 7tsuno (@7tsuno) on CodePen.

なぜか

Vue は要素を可能な限り効率的に描画しようとする。
ここでは二つのtestComponent要素が同じものだとされ、初期化処理が走らないようになっている。

解決策

コンポーネントに別々のkeyをつける。
keyをつけることでvueに"この2つの要素は完全に別個のもので、再利用しないでください"と伝えることが出来る。

Main.vue
<template>
  <div>
    <button @click="click">Click</button>
    <div>
      <testComponent value="a" v-if="testOpen" key="testA"/>
      <testComponent value="b" v-else key="testB"/>
    </div>
  </div>
</template>

<script>
import testCompoment from "TestComponent"

export default {
  data() {
    return {
      testOpen: false
    }
  },
  components: {
    testComponent
  },
  methods: {
    click() {
      this.testOpen = !this.testOpen;
    }
  }
};
</script>

参考

公式 : 条件付きレンダリング

10
6
2

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
10
6