2021年8月5日にVue 3.2がリリースされました。CompositionAPIのシンタックスシュガーが安定版になったり色々と嬉しい内容でした。
そんな中、v-memoというディレクティブが実装されています。とても地味な機能で活躍するシーンは少ないものの、特定のシーンにおいてはパフォーマンスの改善に役立つ重要な機能となるので、今回はv-memo ディレクティブをわかりやすく解説してみたいと思います。
v-memoってなに
リリースノートによると「テンプレートツリーの一部をメモ化する機能」と説明されています。メモ化と言われてもよくわかりませんね。
簡単に言うとv-memoディレクティブが付与されたノード内のDOMは更新されないなくなる、という挙動になります。つまりv-onceディレクティブを付与した場合と同じなのですが、v-memoはvalueにbooleanの配列を設定することができます。
v-memoは設定された配列内の値がすべてtrueになった場合にv-onceと同様の効果を発揮します。
デモ
わかりやすく説明するためにデモを作ってみました。
10件の要素を画面に表示して、フォームによって各要素のnameを編集できるようにします。編集内容を適用する際にv-memoによってDOMを更新する領域を限定しています。
<script setup>
import { ref } from 'vue';
const list = ref([
{ id: 1, name: 'LABEL 1' },
{ id: 2, name: 'LABEL 2' },
{ id: 3, name: 'LABEL 3' },
{ id: 4, name: 'LABEL 4' },
{ id: 5, name: 'LABEL 5' },
{ id: 6, name: 'LABEL 6' },
{ id: 7, name: 'LABEL 7' },
{ id: 8, name: 'LABEL 8' },
{ id: 9, name: 'LABEL 9' },
{ id: 10, name: 'LABEL 10' },
]);
const selected = ref(0);
const text = ref('');
function clickHandler() {
list.value.find((x) => x.id === selected.value).name = text.value;
// v-memoの判定を発生させてDOMを更新する
selected.value = 0;
text.value = '';
}
</script>
<template>
<select v-model="selected">
<option></option>
<template v-for="item in list" :key="item.id">
<option :value="item.id">{{ item.id }}</option>
</template>
</select>
<input type="text" v-model="text" />
<button @click="clickHandler">Apply</button>
<div class="wrapper">
<div
class="badge"
v-for="item in list"
:key="item.id"
v-memo="[item.id !== selected]"
>
<div>
{{ item.name }}
</div>
</div>
</div>
</template>
<style scoped>
button,
input[type='text'] {
margin-left: 0.5rem;
}
.wrapper {
display: flex;
flex-wrap: wrap;
gap: 30px 20px;
margin-top: 2rem;
width: 700px;
}
.badge {
background-color: #eee;
padding: 0.2rem 1rem;
border-radius: 5px;
}
</style>
上記のソースを実行するとブラウザには以下のような画面が表示されます。この状態では各要素のv-memo値はtrueとなるので、全てv-once状態となり以降のレンダリングでDOMの更新はされません。
2番目のラベルを編集してみます。
Applyボタンをクリックすると2番目のラベルが更新されました。(DOMが更新された)
この時、ラベル2以外のDOMはv-memoがtrueなので更新されていないことになります。さらに次は8番目のラベルを編集してみます。
Applyボタンをクリックすると8番目のラベルが更新されました。(DOMが更新された)
以上の通り、v-memoディレクティブは設定された配列が真の場合にのみ発動し、またその真偽が変更されたタイミングでDOMを更新する、という特性があります。
まとめ
デモの通り、v-memoは大量にリストされた子要素の中で必要なDOMのみ更新させることで、レンダリングにかかるコストを抑えてパフォーマンスを最適化します。
デモでは10件のリストでしたが、公式リファレンスによると1000件以上のリストで効果が発揮されるそうです。
1000件以上のリストを扱うケースはそう多くないかもしれませんが、パフォーマンスの低下に悩んだ際はv-memoディレクティブの採用を検討してみてはいかがでしょうか。
以上