Skip to content

よくあるアンチパターン

Next.jsでよくあるアンチパターンと、実際に事故った構造を詳しく解説します。

A. サーバーサイドでのメモリリーク

Section titled “A. サーバーサイドでのメモリリーク”
// ❌ アンチパターン: サーバーサイドでのメモリリーク
const cache = new Map<string, any>();
export async function getServerSideProps() {
// 問題: キャッシュが削除されず、メモリリークが発生
const key = 'data';
if (!cache.has(key)) {
const data = await fetch('https://api.example.com/data').then(r => r.json());
cache.set(key, data);
}
return {
props: {
data: cache.get(key),
},
};
}

なぜ事故るか:

  1. キャッシュの削除: キャッシュが削除されず、メモリリークが発生
  2. メモリ使用量の増加: キャッシュが増加し続け、メモリ使用量が増加
  3. サーバーのクラッシュ: メモリ使用量が増加し、サーバーがクラッシュ

設計レビューでの指摘文例:

【指摘】サーバーサイドでメモリリークが発生しています。
【問題】キャッシュが削除されず、メモリリークが発生しています。
【影響】メモリ使用量の増加、サーバーのクラッシュ
【推奨】TTLを設定し、期限切れのキャッシュを削除する

B. クライアントサイドでのメモリリーク

Section titled “B. クライアントサイドでのメモリリーク”
// ❌ アンチパターン: クライアントサイドでのメモリリーク
'use client';
export default function Page() {
const [data, setData] = useState<any[]>([]);
useEffect(() => {
// 問題: イベントリスナーが削除されない
const handleScroll = () => {
// 処理...
};
window.addEventListener('scroll', handleScroll);
// 問題: クリーンアップ関数がない
}, []);
return <div>Page</div>;
}

なぜ事故るか:

  1. イベントリスナーのリーク: イベントリスナーが削除されず、メモリリークが発生
  2. 参照の保持: クロージャーで参照が保持され、ガベージコレクションが動作しない
  3. ブラウザのクラッシュ: メモリ使用量が増加し、ブラウザがクラッシュ
// ❌ アンチパターン: 大量のデータの取得
export async function getServerSideProps() {
// 問題: 大量のデータを一度に取得
const res = await fetch('https://api.example.com/posts');
const posts = await res.json(); // 10,000件のデータ
return {
props: {
posts, // 10,000件のデータをpropsに渡す
},
};
}
export default function PostsPage({ posts }: { posts: Post[] }) {
return (
<div>
{posts.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}

なぜ事故るか:

  1. メモリ使用量の増加: 大量のデータをメモリに保持し、メモリ使用量が増加
  2. DOMノード数の増加: 大量のDOMノードが作成され、レンダリングパフォーマンスが低下
  3. ネットワーク負荷の増加: 大量のデータを一度に取得し、ネットワーク負荷が増加

設計レビューでの指摘文例:

【指摘】大量のデータを一度に取得しています。
【問題】10,000件のデータを一度に取得し、メモリ使用量が増加しています。
【影響】メモリ使用量の増加、レンダリングパフォーマンスの低下
【推奨】ページネーションを使用してデータを分割する
// ❌ アンチパターン: バンドルサイズの増加
import HeavyLibrary from 'heavy-library';
import AnotherHeavyLibrary from 'another-heavy-library';
export default function Page() {
// 問題: すべてのライブラリがバンドルに含まれる
const result = HeavyLibrary.process();
const anotherResult = AnotherHeavyLibrary.process();
return <div>Page</div>;
}

なぜ事故るか:

  1. バンドルサイズの増加: すべてのライブラリがバンドルに含まれ、バンドルサイズが増加
  2. 初回ロード時間の増加: バンドルサイズが増加し、初回ロード時間が増加
  3. メモリ使用量の増加: すべてのライブラリがメモリにロードされ、メモリ使用量が増加

設計レビューでの指摘文例:

【指摘】バンドルサイズが過剰です。
【問題】すべてのライブラリがバンドルに含まれています。
【影響】初回ロード時間の増加、メモリ使用量の増加
【推奨】動的インポートを使用してコード分割する

よくあるアンチパターンのポイント:

  • A. サーバーサイドでのメモリリーク: キャッシュが削除されず、メモリリークが発生 → サーバーのクラッシュ
  • B. クライアントサイドでのメモリリーク: イベントリスナーが削除されない → ブラウザのクラッシュ
  • C. 大量のデータの取得: 大量のデータを一度に取得 → メモリ使用量の増加、レンダリングパフォーマンスの低下
  • D. バンドルサイズの増加: すべてのライブラリがバンドルに含まれる → 初回ロード時間の増加

これらのアンチパターンを避けることで、安全で信頼性の高いNext.jsアプリケーションを構築できます。

重要な原則: 「正常に動く」よりも「異常時に安全に壊れる」ことを優先する。