本記事では、Vue3におけるv-ifやv-forの使い方、
v-showとの違い、v-forのアンチパターンについて紹介します。
Vue.jsでは、普通のプラグラミング言語のように、
v-ifなどのような条件分岐のコードを書くことができます。
そんな条件分岐のコードとして、
Vue.jsには、v-ifやv-showなどがあります。
本記事では、これらの特徴や違い、
v-forについても解説していきます。
条件付きレンダリング
Vue.jsにおける、
ifなどの条件分岐の文は、
ドキュメントだと、
条件付きレンダリングとされています。
https://ja.vuejs.org/guide/essentials/conditional.html
以下、これら条件付きレンダリングについて、
触れていきます。
v-ifとは?
v-ifは、条件に応じて要素を表示または非表示にするためのディレクティブです。
(ディレクティブ自体の解説については、こちらの記事をご参考ください。)
v-ifを使用することで、動的に要素を表示/非表示することができます。
以下は、v-ifを使用したサンプルコードです。
<template>
<div>
<p v-if="isDisplayed">表示されます</p>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const isDisplayed = ref(true)
</script>
上記のコードでは、isDisplayedというrefを使用して、p要素が表示されるかどうかを動的に制御しています。
このように、v-ifを使用することで、条件に応じた要素の表示/非表示を実現することができます。
(ref(リアクティブ)についての参考記事はこちらです)
TypeScriptなどのif文と同様に、
else-ifやelseを使用することもできます。
<template>
<div>
<p v-if="isDisplayed >= 80">80以上</p>
<p v-else-if="isDisplayed >= 70">70以上</p>
<p v-else-if="isDisplayed >= 60">60以上</p>
<p v-else>不明</p>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
const isDisplayed = computed(() => {
return Math.round(Math.random() * 100)
})
</script>
ただ、else-ifとかelseを使う場合は、
タグを連続で記述する必要があります。
そのため、下記のようなコードは書けません。
<!-- 下記は不可 -->
<template>
<div>
<p v-if="isDisplayed >= 80">80以上</p>
<p>いいね</p>
<p v-else-if="isDisplayed >= 70">70以上</p>
<p v-else-if="isDisplayed >= 60">60以上</p>
<p v-else>不明</p>
</div>
</template>
Vue.jsは、このようにHTML側に
直感的にifとかを書けるので、
わかりやすいですね。
次に、v-ifと似たような条件分岐のディレクティブである、
v-showについて解説します。
v-showとは?
v-showも、v-ifと似たようなディレクティブで、
条件に合致した場合に、表示するようなものです。
<template>
<div>
<p v-show="isDisplayed">表示されます</p>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const isDisplayed = ref(true)
</script>
さて、これだけ見ると、
v-ifとv-showはほとんど違いがないような気もします。
実際、この2つの違いは、
あるにはありますが、ものすごく大きな差異とまでは
言えないと思います。
v-showとv-ifは何が違うか?
v-showは、条件に応じて要素を表示または非表示にするためのディレクティブです。
v-ifとの違いは、v-ifは条件に応じてDOM要素を削除するのに対し、
v-showはdisplayプロパティを制御するため、要素自体は削除されずに表示/非表示が切り替わります。
つまり、v-showは、表示/非表示を切り替える際に、
DOM要素を再描画する必要がないため、より効率的です。
<template>
<div>
<p v-if="isDisplayed">表示されます</p>
<p v-show="isDisplayed">表示されます</p>
<p v-if="isDisplayed2">表示されない</p>
<p v-show="isDisplayed2">表示されない</p>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const isDisplayed = ref(true)
const isDisplayed2 = ref(false)
</script>
この場合、表示されますの部分だけ画面に表示されます。
違いは、表示されないと記載している、
pタグ部分にあって、
これをGoogle developer toolsなどで、
HTML構造を確認すると、
<!--v-if-->
<p style="display: none;">表示されない</p>
とv-showの場合は、
レンダリングされた上で、styleで非表示にしていることがわかります。
なので、表示/非表示の切り替えコストがかかる場合は、
v-showの方が効率的といった感じです。
しばしば言及される、v-ifとv-showの違い問題ですが、
正直私は、この違いをクリティカルに利用した場面に出会ったことがありません。
面倒くさかったら、基本v-ifを使い、
なんかv-ifだといちいち切り替えるときに重い気がするなってときに、
v-showを使えば良い気がします。
リストレンダリング
次にv-forなどのループの方に移って行きたいと思います。
上記の、条件付きレンダリングに対して、
forなどの文は、Vue.jsでは、
リストレンダリングと括られています。
https://ja.vuejs.org/guide/essentials/list.html
以下、これらリストレンダリングについて触れていきます。
v-forとは?
v-forは、配列やオブジェクトの各要素に対して、繰り返し処理を行うためのディレクティブです。
以下は、v-forを使用したサンプルコードです。
<template>
<div>
<ul>
<li v-for="(item, index) in items" :key="item">{{ item }}</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const items = ref(['りんご', 'バナナ', 'みかん'])
</script>
上記のコードでは、itemsという配列の各要素を繰り返し処理し、li要素を生成しています。
v-forを使用することで、配列やオブジェクトを簡単に表示することができます。
構文自体は、item in itemsという風に、inの後にループさせたい変数を持ってきて、
inの前にループ内部で使用したい変数を格納する感じです。
v-forの文法自体は、
Pythonに似ているので、
比較的わかりやすいですね。
key
さて、ここまでは意外と素直なv-forですが、
面倒くさいのが、:keyの部分です。
https://ja.vuejs.org/guide/essentials/list.html#v-for-with-v-if
Vueの場合、v-forを使う際、
こうしたkeyを指定する必要があります。
さて、これの面倒なところは、
これ実は、指定しなくてもエラーにはならないです。
じゃあ、よくねって思いますよね?
(私は最初そう思いました。)
ただ、v-forでkeyを指定しないのは、明らかなアンチパターンになっており、
公式ドキュメントでは、なんとしても守ってくださいと言われています。
https://ja.vuejs.org/style-guide/rules-essential.html#use-detailed-prop-definitions
じゃあ、そもそもこのkeyってなんなの?って感じだと思いますが、
ぶっちゃけ詳細は現時点では追わなくて大丈夫です。
割とVue内部に関わる話なので、最初のうちは混乱するだけになりがちです。
(私がそうでした)
なので、めちゃくちゃざっくり説明すると、
keyは、v-forのデータ項目が変更とか更新とかされた際に、
Vue側が一意な何かの値で個々の要素を識別するために必要といった感じです。
すみません、これでもまだわかりにくいですよね。
要は、keyは割と文字通りの意味で、一意な値を設定することで、
要素を識別できるようにしているわけです。
なので、keyには一意な値を設定する必要があります。
(そうじゃないと、要素を識別できないですもんね)
まあ、平たく言うと、
Vueのv-forのアルゴリズムが、
要素の順序とかの識別をkeyがある場合とない場合で選り分けていて、
その設計上基本的にはkeyが必要みたいな感じですかね。
https://ja.vuejs.org/api/built-in-special-attributes.html#key
たしか、keyを指定しないと、
ESLintとかでも警告が出ていたはずなので、
基本的には指定しましょう。
余談ですが、Vue.jsのアンチパターンという意味では、
v-ifとv-forを一緒に使うというのも存在します。
これも、避けるべきスタイルの一つとして
定義されているので、気をつけたいですね。
https://ja.vuejs.org/style-guide/rules-essential.html#avoid-v-if-with-v-for