問題
早速ですが以下のコードを見てください。
カウントアップボタンを1回クリックした際に、最初に出力される数字は何でしょう?
出力している部分はcomponents/Counter.vue
の①の部分です。
(A) 0
(B) 1
(C) 2
(D) 何も出ない
<template>
<div>
<counter v-if="counter > 0" />
<button type="button" @click="increment">カウントアップ</button>
</div>
</template>
<script lang="ts">
import { defineComponent, inject, provide } from "@nuxtjs/composition-api";
import useCounterStore, { CounterStore, CounterStoreKey } from "~/stores/CounterStore";
import Counter from "~/components/Counter.vue";
export default defineComponent({
components: { Counter },
setup() {
provide(CounterStoreKey, useCounterStore());
const { counter } = inject(CounterStoreKey) as CounterStore;
const increment = () => counter.value++;
return {
counter,
increment
};
},
});
</script>
<template>
<div>{{ counter }}</div>
</template>
<script lang="ts">
import { defineComponent, inject, watch } from "@nuxtjs/composition-api";
import { CounterStore, CounterStoreKey } from "~/stores/CounterStore";
export default defineComponent({
setup() {
const { counter } = inject(CounterStoreKey) as CounterStore;
watch(counter, () => console.log(counter.value)); // ①
return {
counter,
};
},
});
</script>
import { InjectionKey, ref } from "@nuxtjs/composition-api"
const useCounterStore = () => {
const counter = ref(0)
return { counter }
}
export type CounterStore = ReturnType<typeof useCounterStore>
export const CounterStoreKey: InjectionKey<CounterStore> = Symbol('CounterStore')
export default useCounterStore
正解
(D)の「何も出ない」です。
理由
この問題のカギとなるのは、v-if
です。
pages/index.vue
で、components/Counter.vue
の表示に、v-if
を利用しています。
Vue.jsを使ったことがある人だったらわかると思いますが、v-if
は特定の条件の場合のみ表示するためのディレクティブです。
今回の場合、counter > 0
の場合に表示されるようになっているので、初期表示時はcounter = 0
なので表示されないようになっています。さらに、v-ifはHTMLタグ自体も出力しないため、Counterコンポーネントがページ上にない状態です。つまり、watch
も動作しないため、0 → 1の変更の検知はできないということになります。
最初のカウントアップで、counter
が1となり、Counterコンポーネント が表示されwatch
が設定されるようになり、以降、カウンターの変更を検知しwatch
で指定した関数が実行されます。
どうすればよいか
v-if
ではなく、v-show
を使うことで、問題を解決できます。v-show
はHTML自体は出力され、CSSのdisplay
で表示切り替えを行います。Counterコンポーネント自体は出力されているので、画面上見えてなくても、watch
は動くようになります。