Next.js(App Router)初心者が、Server/Client と CSR/SSR/SSG/ISR を手を動かして理解した話
はじめに
React は普段書いているけれど、Next.js はほぼ未経験。
そこで今回は、最小TODOアプリを作りながら次を理解することを目標にしました。
- Server Component / Client Component の違い
- CSR / SSR / SSG / ISR の違い
- 状態管理ライブラリ(Zustand)の最小導入
「動いた」で終わらせず、なぜそう動くかまで言語化することを意識しました。
作ったもの(最小構成)
app/todos/page.tsxapp/components/TodoForm.tsxapp/components/TodoList.tsxapp/components/TodosClient.tsxapp/components/useTodoStore.ts
ポイントは、page.tsx を Server Component のままにして、状態管理と操作を TodosClient に寄せたことです。
Server/Client と CSR/SSR/SSG/ISR は別の話
最初に混乱したのはここでした。結論は次です。
- Server/Client Component
- 「どこでコンポーネントを実行するか」の話
- CSR/SSR/SSG/ISR
- 「ページをいつ生成するか」の話
つまり、同じ概念ではないです。
page.tsx でレンダリング方式を実験
renderedAt(サーバ描画時刻)を表示して挙動を確認しました。
SSG(静的)
export const dynamic = "force-static";
npm run build && npm run start- リロードしても renderedAt が固定
- 結論: ビルド時に生成されたHTMLを配信
SSR(動的)
export const dynamic = "force-dynamic";
- リロードごとに renderedAt が変わる
- 結論: 毎リクエストでサーバレンダリング
ISR(間隔更新)
export const revalidate = 60;
- 60秒以内は同じ表示
- 60秒超過後のアクセスで再生成
- 結論: 静的配信ベースで定期更新
なぜ build + start で確認したのか
npm run devは開発体験(HMR)優先npm run buildは本番成果物を作るnpm run startは成果物を本番モードで配信する
レンダリング方式の差分確認は、本番モードが正確でした。
ライフサイクル理解(関数とクラス)
比較用に2ページを作りました。
/class-sample(クラス)/function-sample(関数)
確認したこと:mount: 初回表示update: state/props更新unmount: 画面から消える
関数コンポーネントでは useEffect の cleanup を使います。
useEffect(() => {
console.log("mounted");
return () => {
console.log("unmounted");
};
}, []);
cleanup は「後片付け」です。イベント解除やタイマー停止をしないと、バグやリークの原因になります。
Zustand を入れて感じたこと
最小導入ではかなり分かりやすかったです。
export const useTodoStore = create<TodoState>((set) => ({
todos: initialTodos,
addTodo: (title) =>
set((state) => ({
todos: [...state.todos, { id: Date.now(), title }],
})),
deleteTodo: (id) =>
set((state) => ({
todos: state.todos.filter((todo) => todo.id !== id),
})),
}));
set で状態更新
追加は「配列を増やす」
削除は「配列を絞る」
Redux Toolkitより、最初の体験としてはZustandの方が速く理解できました。
CSR / SSR / SSG / ISR を要件で選ぶ基準
CSR
操作が多いUI、管理画面向き
SSR
常に最新性が必要なページ向き
SSG
更新頻度が低く、速度重視のページ向き
ISR
速度と鮮度のバランスを取りたいページ向き
一言まとめ: 鮮度重視=SSR、速度/コスト重視=SSG、中間バランス=ISR。
まとめ
Next.js は「Reactを書く」だけでなく、表示責務(Server/Client)と生成タイミング(SSR/SSG/ISR)を設計するフレームワークだった
renderedAt のような観測ポイントを置くと理解が深まる
小さく作って、構造を読んで、少し触る進め方が最も効率的だった
次は、この構成を保ったまま fetch を追加して、キャッシュ戦略まで学習したいと思います。

コメント