はじめに
Vue.js を使ったアプリ開発では、パフォーマンスの最適化が重要です。アプリが 重くなる主な原因 としては、次のようなものがあります。
- 不要なリレンダリング(無駄な状態更新)
- 無駄なデータ取得(API の過剰な呼び出し)
- 大きなバンドルサイズ(初回ロードの遅延)
パフォーマンスを最適化することで、UX 向上・ページ速度改善・メモリ使用量の削減 につながります。
Vue の高速化テクニック
Vue では、次の方法でパフォーマンスを向上させることができます。
computed() を活用して無駄な再計算を防ぐ
リアクティブなデータを直接テンプレート内で計算すると、毎回レンダリングされるたびに計算されてしまう ため、パフォーマンスが低下します。
computed()
を使うことで、依存するデータが変わったときのみ計算が実行され、結果がキャッシュ されます。
<script setup>
import { ref, computed } from 'vue';
const price = ref(1000);
const taxRate = ref(0.1);
// 価格が変更されたときのみ再計算
const totalPrice = computed(() => price.value * (1 + taxRate.value));
</script>
v-if と v-show の使い分け
Vue では、要素を表示/非表示にするために v-if
と v-show
を使いますが、それぞれの動作が異なります。
v-if | v-show | |
---|---|---|
仕組み | DOM に要素を追加/削除 | CSS で display: none |
適しているケース | 条件によって要素を完全に消す場合 | 頻繁に表示/非表示を切り替える場合 |
レンダリングコスト | 高い(要素を追加/削除) | 低い(CSS のみ変更) |
<template>
<p v-if="isVisible">v-if は DOM の追加削除を行う</p>
<p v-show="isVisible">v-show は CSS の display: none を適用する</p>
</template>
イベントのデバウンス処理
検索機能や入力フォームで、ユーザーが キーを押すたびに API を呼び出す と無駄なリクエストが増えます。
これを防ぐために「デバウンス」を活用します。
<script setup>
import { ref } from 'vue';
const keyword = ref('');
let timer = null;
const search = () => {
clearTimeout(timer);
timer = setTimeout(() => {
console.log(`検索実行: ${keyword.value}`);
}, 500); // 0.5秒ごとに実行
};
</script>
<template>
<input v-model="keyword" @input="search" placeholder="検索..." />
</template>
ユーザーが入力を終えて 0.5 秒経過するまで検索を実行しません!
keep-alive で不要なリレンダリングを防ぐ
Vue の keep-alive
を使うと、コンポーネントの 状態をキャッシュ し、不要なリレンダリングを防ぐことができます。
特に Vue Router でページを切り替えるとき や タブ切り替えのような UI で有効です。
keep-alive の基本的な使い方
通常、<router-view />
の中のコンポーネントは ページを切り替えるたびに破棄され、再作成されます。
しかし、<keep-alive>
で囲むと、一度表示したコンポーネントはメモリに保持され、再描画されなくなります。
<template>
<keep-alive>
<router-view />
</keep-alive>
</template>
ページを切り替えても、コンポーネントの状態が保持される!
無駄なリレンダリングがなくなり、パフォーマンスが向上!
keep-alive が効果的な場面
- タブ切り替えのような UI
- 検索結果などのキャッシュを残したい場合
- リスト画面と詳細画面を行き来するとき
- フォーム入力を途中で保存し、戻っても消えないようにする
たとえば、以下のようにタブ切り替えを keep-alive
で最適化できます。
<template>
<div>
<button @click="currentTab = 'tab1'">タブ1</button>
<button @click="currentTab = 'tab2'">タブ2</button>
<keep-alive>
<component :is="currentTabComponent" />
</keep-alive>
</div>
</template>
<script setup>
import { ref, defineAsyncComponent } from 'vue';
const currentTab = ref('tab1');
const currentTabComponent = computed(() =>
currentTab.value === 'tab1' ? Tab1 : Tab2
);
const Tab1 = defineAsyncComponent(() => import('./Tab1.vue'));
const Tab2 = defineAsyncComponent(() => import('./Tab2.vue'));
</script>
keep-alive
によって、タブの内容がキャッシュされるため、不要な再描画を防げる!
keep-alive を使うと mounted() は最初の 1 回しか実行されない
通常、コンポーネントは 表示されるたびに mounted()
が実行 されますが、keep-alive
を適用すると 最初の 1 回しか実行されなくなります。
つまり、コンポーネントの表示・非表示に合わせて何か処理をしたい場合は、activated()
/ deactivated()
フックを使う必要があります。
activated() / deactivated() の使い方
onActivated()
→keep-alive
されたコンポーネントが再表示されるときに実行されるonDeactivated()
→keep-alive
されたコンポーネントが非表示になるときに実行される
タブを切り替えたときにログを出力
<script setup>
import { onActivated, onDeactivated } from 'vue';
onActivated(() => {
console.log('🔵 コンポーネントが表示されました');
});
onDeactivated(() => {
console.log('🔴 コンポーネントが非表示になりました');
});
</script>
onActivated()
は、ページを戻ってきたときに実行されるonDeactivated()
は、ページを離れるときに実行される
たとえば、ページを切り替えたときに API を再取得する ような処理も可能です。
API データをキャッシュしつつ、タブを切り替えたら再取得する
<script setup>
import { ref, onMounted, onActivated } from 'vue';
import axios from 'axios';
const data = ref(null);
const fetchData = async () => {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
data.value = response.data;
};
// 初回のみ API を取得
onMounted(fetchData);
// ページを戻ってきたときに API を再取得
onActivated(fetchData);
</script>
<template>
<div>
<p v-if="data">{{ data.title }}</p>
</div>
</template>
- 初回の
onMounted()
で API を取得 - タブを戻ってきたときに
onActivated()
でデータを更新 keep-alive
によって、タブを切り替えてもデータが残る!
v-memo や Lazy Loading の活用
Vue 3 では、パフォーマンスを最適化するための新機能として v-memo
が導入され、また Lazy Loading(遅延読み込み) を活用することで、アプリの初回ロードを高速化できます。
v-memo(Vue 3 の新機能)
Vue 3 の v-memo
ディレクティブを使うと、特定の値が変わらない限り要素を再レンダリングしない ようにできます。
これにより、不要な再描画を減らし、パフォーマンスを向上 させることが可能です。
v-memo の基本的な使い方
<template>
<div v-memo="[count]">
<p>{{ count }}</p>
</div>
</template>
count
の値が変わらない限り、この<div>
内の要素は 再レンダリングされません!
v-memo の動作を確認する
<script setup>
import { ref } from 'vue';
const count = ref(0);
const otherValue = ref(0);
</script>
<template>
<div v-memo="[count]">
<p>カウント: {{ count }}</p>
</div>
<button @click="count++">count を増やす</button>
<button @click="otherValue++">otherValue を増やす</button>
</template>
otherValue
を増やしても、v-memo="[count]"
を設定している部分は再描画されません!count
の値が変わったときのみ、この要素が更新されます。
v-memo を使うメリット
- リスト要素の再描画を防ぐ(特に大規模リストで有効)
- 複雑な UI の再レンダリングを抑えてパフォーマンスを向上
- 無駄な DOM 操作を減らして、CPU 処理の負荷を軽減
Lazy Loading(遅延読み込み)
Lazy Loading(遅延読み込み)とは、必要なときにのみコンテンツをロードする 手法です。
これにより、ページの初回ロードを高速化し、不要なリソースの読み込みを抑える ことができます。
画像の遅延読み込み(Lazy Loading)
画像はサイズが大きく、特に多くの画像を含むページでは すべての画像を最初に読み込むとパフォーマンスが低下 します。
そのため、スクロール時に 必要な画像だけを遅延ロードする(Lazy Load) のが一般的です。
通常の画像読み込み
<img src="image.jpg" alt="通常の画像" />
- ページがロードされるとすぐに
image.jpg
をダウンロードする - すべての画像を一度に読み込むため、ページが重くなる
遅延読み込み(Lazy Loading)
v-lazy
などのライブラリを使って スクロール時に画像を読み込む ことができます。
<img v-lazy="imageUrl" />
- スクロールしたときに初めて画像が読み込まれる!
- 不要な画像を最初に読み込まないため、ページの読み込み速度が向上!
Vue 公式では
v-lazy
は提供されていませんが、vue-lazyload
などのライブラリを使うことで実装可能です。
コンポーネントの遅延読み込み
Vue では、コンポーネントを 動的に遅延ロード(Lazy Load) することができます。
これにより、初回ロード時にすべてのコンポーネントを読み込むのではなく、必要なときにだけロードする ことができます。
defineAsyncComponent() を使ったコンポーネントの遅延読み込み
<script setup>
import { defineAsyncComponent } from 'vue';
const LazyComponent = defineAsyncComponent(() => import('./MyComponent.vue'));
</script>
<template>
<LazyComponent />
</template>
- 初回ロード時に
MyComponent.vue
をダウンロードしない LazyComponent
が初めて表示されたタイミングでロードされる- バンドルサイズを削減し、ページ表示を高速化できる
遅延読み込み時にローディング表示を追加
defineAsyncComponent()
は loadingComponent
を指定することで、ロード中に表示するコンポーネントを設定 できます。
<script setup>
import { defineAsyncComponent } from 'vue';
// 遅延ロードするコンポーネント
const LazyComponent = defineAsyncComponent({
loader: () => import('./MyComponent.vue'),
loadingComponent: () => import('./LoadingSpinner.vue'),
delay: 200, // 200ms 待ってからローディング表示
});
</script>
<template>
<LazyComponent />
</template>
- コンポーネントが読み込まれるまで「ローディングスピナー」を表示
- ユーザーに「読み込み中」であることを伝えられるので UX 向上
Chrome DevTools を使ったパフォーマンス測定
- F12キー(開発者ツール)を開く
- Performance タブで「Record」をクリック
- アプリを操作してパフォーマンスを計測
- 不要なリレンダリングが発生していないか確認
まとめ
computed()
を使い、無駄な計算を防ぐv-if
とv-show
を適切に使い分けるwatch()
の代わりにdebounce()
を活用し、不要なリクエストを削減keep-alive
を使ってコンポーネントの再レンダリングを防ぐv-memo
を活用し、不要な描画を減らす- コード分割(遅延読み込み)を行い、バンドルサイズを削減
これらのテクニックを活用することで、Vue.js アプリのパフォーマンスを大幅に向上させることができます!
コメント