たぶんすごい基礎中の基礎なんだろうけど、結構詰まったので。
どういうことか
例えばこんなコンポーネントがあるとする。
渡した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>