9
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue 3.2で追加されたv-memoについて解説してみる

Last updated at Posted at 2021-12-17

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の更新はされません。
スクリーンショット_2021-10-12_16.28.04.png
2番目のラベルを編集してみます。
スクリーンショット_2021-10-12_16.28.27.png
Applyボタンをクリックすると2番目のラベルが更新されました。(DOMが更新された)
スクリーンショット_2021-10-12_16.28.39.png
この時、ラベル2以外のDOMはv-memoがtrueなので更新されていないことになります。さらに次は8番目のラベルを編集してみます。
スクリーンショット_2021-10-12_16.29.02.png
Applyボタンをクリックすると8番目のラベルが更新されました。(DOMが更新された)
スクリーンショット_2021-10-12_16.29.10.png
以上の通り、v-memoディレクティブは設定された配列が真の場合にのみ発動し、またその真偽が変更されたタイミングでDOMを更新する、という特性があります。

まとめ

デモの通り、v-memoは大量にリストされた子要素の中で必要なDOMのみ更新させることで、レンダリングにかかるコストを抑えてパフォーマンスを最適化します。
デモでは10件のリストでしたが、公式リファレンスによると1000件以上のリストで効果が発揮されるそうです。

1000件以上のリストを扱うケースはそう多くないかもしれませんが、パフォーマンスの低下に悩んだ際はv-memoディレクティブの採用を検討してみてはいかがでしょうか。

以上

9
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?