「v-memo」と「v-once」によって解決できる問題
Vueは、大きく以下のような手順で再レンダリングをしています。
-
データの変更
OptionsAPIで言うところのdata
、CompositionAPIで言うところのref
やreactive
などのデータオブジェクトが変更されると、その変更が検出されます。 -
仮想DOMの生成
新しい「仮想DOM」を生成します。仮想DOMは、実際のDOMの軽量コピーで、どこが変更されたかを効率的に計算するために使用されます。 -
差分計算
(2)で生成された新しい仮想DOMと、その前に生成された仮想DOMを比較して、どの部分が変更されたかを計算します。 -
DOMの更新
(3)にて算出した差分を、実際のDOMに対して適用します。(このプロセスは「patch」、「diffing」、「reconciliation」とも呼ばれています)
DOMはツリー状で形成されます。親にあたる要素が再レンダリングされた場合、その子要素も一緒に再レンダリングされてしまいます。
子要素に多くの要素を含む場合、この不要な再レンダリングがパフォーマンスの低下に繋がることがあります。
このような、不要な再レンダリングを制御する為に使用されるのが、今回紹介する「v-once」と「v-memo」です。
v-once
<template>
<h1 v-once>Welcome to my page!</h1>
</template>
v-once
は、それを適用した要素とその子要素にあたるものは全て、初回のみレンダリングを行い、再レンダリングを実行しないようにすることができるディレクティブです。
たとえ依存するデータが変更されたとしても、再レンダリングは実行されないので表示は更新されません。
使い所としては、「ref
やreactive
などのデータ更新によって再レンダリングされる必要のない要素」に対して適用します。
v-memo
<template>
<div v-memo="[valueA, valueB]">
...
</div>
</template>
無条件で再レンダリングをさせないv-once
に対して、再レンダリングに条件をつけられるのが、バージョン3.2より利用可能になったv-memo
です。
指定された配列内のデータが更新された場合にのみ、再レンダリングを実行します。もし空配列を渡した場合は、v-once
と同様の挙動になります。
大きなコンポーネントの再レンダリングをコントロールするのに便利です。
使い所としては、以下のようなv-for
を用いて作成されたリストに対して使用します。
<div v-for="item in items" :key="item.id" v-memo="[items]">>
<p>{{ item.id }}: {{ item.name }}</p>
</div>
公式ドキュメントによるとv-memo
は、1000件を超えるリストに対して使用すると効果を発揮するそうです。
あまり1000件を超えるリストを扱うことは無さそうですが、もし膨大な量のリストを扱う際にはv-memo
の利用を検討してみてください。
v-memo は、パフォーマンスが重要なシナリオでのミクロな最適化を行うためにのみ提供されており、ほとんど必要ありません。この機能が役に立つ最も一般的なケースは、大きな v-for リスト(length > 1000)をレンダリングするときです
v-for
と併用する際には、v-for
を付与した要素にv-memo
を付与してください。以下のようにv-for
の内部でv-memo
を使用することはできません。
<div v-for="item in list" :key="item.id">
<p v-memo="[list]">{{ item.id }}: {{ item.name }}</p>
</div>