👌
【Next.js 15】基本の概念まとめ
App Router
主に、2つの機能がある
-
app
ディレクトリ基準の新しいルーティング - RSCレンダリングの仕組み
ルーティングの基本
App Routerは以下のルールでルーティングされる
app/
├── layout.tsx // ルートレイアウト
├── page.tsx // ホームページ (/)
├── about/
│ └── page.tsx // /about
├── blog/
│ ├── layout.tsx // /blog 配下の共通レイアウト
│ ├── page.tsx // /blog
│ └── [slug]/
│ └── page.tsx // /blog/xxx
動的ルート
書き方 | URL例 | 受け取る値 |
---|---|---|
[param] | /blog/123 | {param:'123'} |
[...param] | /blog/a/b/c | { param: ['a','b','c'] } |
[[...param]] | /blog/, /blog/a/b | { param: undefined } または ['a','b'] |
特別なファイル
ファイル名 | 役割 |
---|---|
page.tsx | 実際のページ |
layout.tsx | 共通レイアウト |
loading.tsx | ローディングUI |
error.tsx | エラーハンドリング |
not-foud.tsx | 404ページ |
RSC(React Server Components)
- App Router配下のコンポーネントはデフォルトでRSCとなる
- RSCとはサーバーで動くReactコンポーネントだが、コンポーネント単位でサーバーとクライアントを分けて効率よく描画する仕組みをもつ
RSCとSSRの違いは?
RSCはあくまでコンポーネントの種類であり、SSRはレンダリングの種類である。
RSC=サーバーコンポーネント+部分的クライアントコンポーネント
だと理解している。
項目 | SSR | RSC |
---|---|---|
実行場所 | サーバー | サーバー |
生成物 | HTML | HTML + React コンポーネント情報 |
クライアント負荷 | ReactのHydrationが必須で比較的重い | 必要最低限のJSだけで済み軽い |
使いどころ | ページ全体の初期レンダリング | 部分的なコンポーネントのサーバー処理 |
柔軟性 | 制限あり | コンポーネント単位で細かく制御可能 |
Server ComponentsとClient Components
以下のようにコンポーネントを作成するだけでServer Components
である
また、Server Components
はClient Components
を呼び出せる
app/page.tsx
// app/page.tsx
import { ClientButton } from './ClientButton';
export async function Page() {
const message = 'サーバーコンポーネントからこんにちは!';
return (
<>
<h1>{message}</h1>
<ClientButton />
</>
);
}
以下がClient Components
である
use Client
と記述があればクライアントコンポーネント
app/ClinetButton.tsx
'use client';
import { useState } from 'react';
export function ClientButton() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>クリック数: {count}</button>;
}
データ取得方法
✅ 基本的にはServer Components
内でデータを取得することを目指す
データの種類 | 推奨される取得方法 |
---|---|
静的データ(商品一覧など) |
Server Component + fetch() + cache()
|
ユーザー情報 / セッション |
Client Component + React Query / useEffect |
操作による変更(フォーム送信) |
Server Action + router.refresh()
|
変更後のUI反映 |
React Query.invalidate() や revalidatePath()
|
Server Components
- Fetch API
- ORMかdatabase
// lib/api.ts
export const getProducts = cache(async () => {
const res = await fetch('https://api.example.com/products');
if (!res.ok) throw new Error();
return res.json();
});
// app/products/page.tsx
import { getProducts } from '@/lib/api';
import { use } from 'react';
export default function Page() {
const products = use(getProducts());
return (<ProductList items={products} />);
}
Client Components
- React use hook
- 外部ライブラリ利用
- SWRまたはReact Query
'use client';
import { useQuery } from '@tanstack/react-query';
export default function UserProfile() {
const { data, isLoading } = useQuery({
queryKey: ['user'],
queryFn: async () => {
const res = await fetch('/api/user');
return res.json();
}
});
if (isLoading) return <p>Loading...</p>;
return <p>{data.name}</p>;
}
Server Actions
サーバー関数を直接呼び出せる構文
// app/actions.ts
'use server';
export async function submitForm(formData: FormData) {
const name = formData.get('name');
// サーバー側で処理(DB書き込みなど)
console.log(name);
}
// app/page.tsx
import { submitForm } from './actions';
export default function Page() {
return (
<form action={submitForm}>
<input type="text" name="name" />
<button type="submit">送信</button>
</form>
);
}
✅ ここでの submitForm は「サーバー上の関数」だが、直接 action 属性として渡せる。
React Query.invalidate()
React Query のキャッシュを無効化して、クライアントで再フェッチさせる
import { useQueryClient } from '@tanstack/react-query';
const queryClient = useQueryClient();
queryClient.invalidateQueries({ queryKey: ['user'] });
revalidatePath()
Next.js の Server Action で使い、特定のパスのサーバーキャッシュを再生成させる
'use server';
import { revalidatePath } from 'next/cache';
export async function deletePost(id: string) {
await db.delete(id);
revalidatePath('/posts'); // ← /posts を再生成
}
Discussion