👌

【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 ComponentsClient 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内でデータを取得することを目指す
https://nextjs.org/docs/app/getting-started/fetching-data

データの種類 推奨される取得方法
静的データ(商品一覧など) 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