🤔

v-if と v-show のベストプラクティス

に公開

ラブグラフでエンジニアインターンをしているあさいです!

Vue.jsでUIを実装している時に、要素の出し分けをするために、条件付きレンダリングの v-ifv-show を使うケースがあると思います。
今回は、どのような時にどちらを使えばいいのかというのを書いていこうと思います。

使用方法の確認

v-if

通常のように書くと、

<h1 v-if=isHoliday>Happy Holiday!!</h1>

また、template を用いて、

<template v-if=isHoliday>
 <h1>Today is Holiday</h1>
 <p>今日は休日です<p>
</template>

このような形でも記述することができます。
他にも、v-elseと組み合わせて、

<template v-if=isHoliday>
 <h1>Today is Holiday</h1>
 <p>今日は休日なので追加料金0円です!<p>
</template>
<template v-else>
 <h1>Today is Weekday</h1>
 <p>今日は平日なので追加料金500円です!</p>
</template>

このように、表示内容を v-if のTrueかFalseかによって表示内容を変えるといったことができます。
他にも、v-else-if があり、

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

と言った感じで書くことができます。

v-show

v-show も同様に、真偽によって表示する内容を変更することができます。
使用方法は v-if とほぼ同じで、

<h1 v-show=isHoliday>Happy Holiday!!</h1>

このように使用することができます。
ただ v-show にはいくつか注意点があり、

  • v-else と連動しない

    • v-if だと v-else と連動しますが、v-showv-else のような挙動を実装したい場合は、v-show=!isHoliday のように、否定論理演算子を使用する必要があります。
  • <template> 要素をサポートしていない

    • 複数の要素で v-show を使用したい場合は、div タグなどを使用しましょう。

v-if と v-show の動作の違い

v-if の仕組み

v-if は条件が true の時だけ要素を DOM に生成し、条件が false になると DOM から完全に削除されます。
そのため、初期レンダリング時に不要な要素が描画されず、条件が成立しない場合はリソースの無駄遣いを防げます。
ただし、条件が頻繁に変わる場合は、毎回 DOM の生成・破棄が発生するのでパフォーマンス面でのコストが大きくなる可能性があります。

v-show の仕組み

v-show は要素を常に DOM に保持し、表示・非表示の切り替えは単に CSS の display プロパティを変更するだけです。
そのため、要素の生成・削除は行われないので、頻繁に表示状態が変わる場合に効率的です。
ただし、初期レンダリング時は常に DOM に存在するため、初期ロードでのレンダリングコストがやや高くなる可能性があります。

いつどちらを使うべきか

v-if を使うべきケース

条件が初期段階でほぼ固定の場合

例えば、ユーザーの状態や権限に基づいて、一度だけ表示・非表示が決まる要素などは v-if が適しています。

重いコンポーネントの場合

初期にレンダリングしなくてよい、重いコンポーネントを条件に応じて動的に挿入・削除する場合、DOM に余計な要素がないほうがパフォーマンス上有利です。
例として、Three.js や WebGL を利用した3D表示コンポーネントを表示するときです。レンダリングに負荷がかかるコンポーネントは、初期ロード時にレンダリングしなくても良い場合が多いためです。

v-show を使うべきケース

頻繁に表示状態が変わる場合

タブの切り替えやドロップダウンの表示・非表示など、ユーザー操作で瞬時に切り替える必要があるケースでは、DOM の再生成を防ぐ v-show が適しています。

初期ロード後に高速な切り替えが求められる場合

初回のレンダリングは重くなる可能性がありますが、一度描画した後は CSS の切り替えのみで済むため、反応速度が向上します。

DOM の視点からの考察

みんな大好き MDN Web Docs の DOMの紹介 のページにも触れられているように、DOM は Web ページの構造をツリー状に管理しています。
その観点で言うと、v-if は、このツリーに対して「要素の追加」や「削除」を実行します。つまり、条件が変わるたびにツリー構造が動的に更新されることになります。

v-show は、ツリー内に常に要素が存在している状態で、スタイルだけが切り替わるため、ツリーの構造自体は固定されます。

DOM に直接アクセスする外部ライブラリ(たとえば SweetAlert2 や Bootstrap Modal など)は、初期化時に「この DOM 要素はここにあるよ!」といった形で、その要素をキャッシュしておきます。ここでのキャッシュとは、一度取得した DOM ノードの情報を内部に保存しておくことを意味します。

v-if を使った場合、v-if は条件に応じて、実際に DOM ツリーから要素を追加したり削除したりします。そのため、一度キャッシュされた DOM ノードが、条件が変わったタイミングで削除されると、ライブラリは「思っていた要素が見当たらない!」という状況になり、エラーを引き起こす可能性があります。

v-show を使った場合、v-show は常に DOM ツリー内に要素を保持し、CSS(display プロパティ)で表示・非表示を切り替えます。つまり、キャッシュされた DOM ノードは常に存在しているため、外部ライブラリは正しくその要素にアクセスでき、エラーが発生しにくくなります。

まとめると、DOM に直接アクセスするライブラリにとっては、要素が常に存在している v-show の方が、キャッシュされたノードが失われる心配がないため、適していると言えます。

まとめ

v-if

  • 条件が false の場合、DOM から完全に削除されるためリソースの無駄を防げる
  • 条件が頻繁に変わると、毎回 DOM の生成・破棄が発生するためパフォーマンスに影響する可能性がある

v-show

  • 初回レンダリング時には全ての要素が DOM に存在するが、表示非表示は CSS の切り替えのみで済む
  • 頻繁な表示切り替えに向いているが、常に DOM に要素が残るため初期レンダリング時の負荷が大きくなる場合がある

参考文献

https://ja.vuejs.org/guide/essentials/conditional
https://developer.mozilla.org/ja/docs/Web/API/Document_Object_Model/Introduction

ラブグラフのエンジニアブログ

Discussion