ロジック再利用とパフォーマンス最適化
ルーティングとログインロジックを完了した後、プロジェクトの規模が拡大するにつれて、いくつかのロジック(ローカルデータの保存・取得、通知のポップアップなど)が複数のページで繰り返し現れることに気づくでしょう。同時に、タスクリストが数千件に達すると、ページがカクつく可能性があります。
この段階では、私たちは以下を通じてComposition APIの深い応用コード再利用とパフォーマンスボトルネックの問題を解決します。
ロジック再利用:カスタムComposables (Hooks)
ComposablesはVue 3の真髄であり、ロジック(State + Actions)を独立した関数に切り離すことを可能にします。
useLocalStorage:データ永続化ロジックの切り離し
毎回Storeやコンポーネント内で手書きする必要はありませんlocalStorage.getItem。
例
import { ref, watch } from 'vue';
export function useLocalStorage(key, defaultValue = null) {
// 1. データを初期化する
const storedValue = localStorage.getItem(key);
const data = ref(storedValue ? JSON.parse(storedValue) : defaultValue);
// 2. 変更を監視して自動的に同期する
watch(data, (newValue) => {
localStorage.setItem(key, JSON.stringify(newValue));
}, { deep: true });
return data;
}
useNotification:共通UIロジックの切り離し
簡単な通知機能を実装します。
例
import { ref } from 'vue';
export function useNotification() {
const message = ref('');
const isVisible = ref(false);
const notify = (msg, duration = 2000) => {
message.value = msg;
isVisible.value = true;
setTimeout(() => {
isVisible.value = false;
}, duration);
};
return { message, isVisible, notify };
}
パフォーマンスチューニング:大データ量と高頻度レンダリングの処理
あなたのTaskHubが管理するタスクが10件から1000件に増えると、Vueのデフォルトの「深いリアクティブ」は計算負荷をもたらします。
shallowRefとmarkRaw
Vueのデフォルトのrefは再帰的リアクティブです(つまり、オブジェクト内部のすべてのプロパティがプロキシされます)。
shallowRef:.valueの参照変更のみを監視.valueし、オブジェクト内部のプロパティの変化は監視しない。
- シナリオ:バックエンドから大量の読み取り専用タスク履歴を取得する場合。
markRaw:オブジェクトをマークして、それを決してリアクティブに変換されないようにします。
- シナリオ:複雑なサードパーティライブラリのインスタンス(EChartsのチャートインスタンス、地図インスタンスなど)は、リアクティブにラップすると逆にエラーが発生したり、パフォーマンスを極端に消費したりします。
// 性能优化示例
import { shallowRef, markRaw } from 'vue';
// 假设这是一万条历史归档数据
const archiveTasks = shallowRef([]);
const loadArchive = (data) => {
// 仅在赋值时触发一次响应式更新,内部属性修改不触发
archiveTasks.value = data;
};
v-onceとv-memo(ディレクティブレベルの最適化)
v-once:静的コンテンツは一度だけレンダリングする
あるタスクがレンダリング後に変化しない場合(タスクの作成時間など)、v-once。
<span v-once>创建于: {{ task.createdAt }}</span>
- 原理:Vueはレンダリング後、そのノードの後続の更新チェックをスキップします。
v-memo:オンデマンド更新(Vue 3.2+)
これは長いリストを最適化するための最も強力なディレクティブです。依存関係の配列を受け取り、配列内の値が変化したときのみ、そのノードとその子ノードが再レンダリングされます。
<li v-for="task in tasks" :key="task.id" v-memo="[task.isCompleted, task.title]">
{{ task.title }} - {{ task.isCompleted }}
</li>
いつチューニングすべきか?
| 手法 | 解決する問題 | 推奨シナリオ |
|---|---|---|
| Composables | コードの重複、ロジックの散乱 | コンポーネント間でロジックを共有(例:ログインチェック、テーマ切り替え) |
| shallowRef | 大きなオブジェクトの深いプロキシによるメモリオーバーヘッド | リストのデータ量が1000を超え、全体を置き換えるだけでよい場合 |
| v-memo | 頻繁に発生する長いリストの仮想DOM差分比較 | 複雑なv-forリスト、かつ各項目で少数のプロパティのみが変化する |
以前のプロジェクトに組み込む
あなたは試しに「TaskItem.vue」に適用してみてくださいv-memo:
<template>
<li v-memo="[task.id, task.isCompleted]" class="...">
...
</li>
</template>
これで、あなたのプロジェクトはロジックが明確(Composables)なだけでなく、パフォーマンスも強力になります。
その他の拡張