さとまたプログラミングラボ

Next.js

Reactベースの本格的なWebアプリケーションフレームワーク

Next.jsとは?

日常での例え:Reactの「フル装備版」

React単体 = エンジンだけ

UIを作る力はあるが、
ルーティングや最適化は別途必要

Next.js = 完成した車

React + ルーティング + 最適化 +
サーバー機能がセットになっている

なぜNext.jsを使う?Reactだけじゃダメ?

Reactだけで作ると:

  • ルーティング(ページ遷移)を別のライブラリで追加する必要がある
  • SEO対策が難しい(検索エンジンに内容が見えない)
  • 初期表示が遅くなりがち

Next.jsなら:これらを解決!特にSSR(サーバーサイドレンダリング)でSEOとパフォーマンスを両立

重要な用語

SSR(Server Side Rendering):サーバーでHTMLを生成してから送る → SEOに強い、初期表示が速い

SSG(Static Site Generation):ビルド時にHTMLを生成 → 最速、ブログに最適

App Router:Next.js 13以降の新しいルーティング方式。appフォルダを使う

Next.jsでできること

📁

ファイルベースルーティング

特徴

フォルダ構造がそのままURLに

SSR/SSG

重要

サーバーサイドレンダリングと静的生成

🔌

API Routes

便利

バックエンドAPIを同じプロジェクトで

🖼️

画像最適化

便利

next/imageで自動最適化

🚀

自動コード分割

性能

必要なコードだけ読み込み

🔄

Server Components

App Router

サーバーで実行されるコンポーネント

コード例

プロジェクト作成

create-next-appで開始

bash
# プロジェクト作成
npx create-next-app@latest my-app

# 開発サーバー起動
cd my-app
npm run dev
プレビュー
✓ Ready in 2.1s
➜ Local: http://localhost:3000

ページコンポーネント(App Router)

app/page.tsx がトップページ

typescript
// app/page.tsx
export default function HomePage() {
  return (
    <main>
      <h1>Welcome to Next.js!</h1>
      <p>This is the home page.</p>
    </main>
  );
}
プレビュー

Welcome to Next.js!

This is the home page.

動的ルーティング

[id]でパラメータを受け取る

typescript
// app/blog/[slug]/page.tsx
interface Props {
  params: { slug: string }
}

export default function BlogPost({ params }: Props) {
  return (
    <article>
      <h1>記事: {params.slug}</h1>
    </article>
  );
}

// /blog/hello-world → params.slug = "hello-world"
プレビュー
URL: /blog/hello-world

記事: hello-world

データ取得(Server Component)

サーバーで直接データ取得

typescript
// app/posts/page.tsx
async function getPosts() {
  const res = await fetch('https://api.example.com/posts');
  return res.json();
}

export default async function PostsPage() {
  const posts = await getPosts();

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
プレビュー
// Server Componentなので
// クライアントにAPIキーが漏れない

API Routes

app/api/でAPIエンドポイント作成

typescript
// app/api/hello/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json({
    message: 'Hello from API!'
  });
}

export async function POST(request: Request) {
  const body = await request.json();
  return NextResponse.json({ received: body });
}
プレビュー
GET /api/hello
{"message": "Hello from API!"}

Client Component

'use client'でインタラクティブに

typescript
// components/Counter.tsx
'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}
プレビュー

Layoutコンポーネント

共通レイアウトを定義

typescript
// app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body>
        <header>ヘッダー</header>
        <main>{children}</main>
        <footer>フッター</footer>
      </body>
    </html>
  );
}
プレビュー
ヘッダー
ページ内容
フッター

App Routerのディレクトリ構造

my-app/
├── app/
│   ├── layout.tsx      # ルートレイアウト
│   ├── page.tsx        # トップページ (/)
│   ├── about/
│   │   └── page.tsx    # /about
│   ├── blog/
│   │   ├── page.tsx    # /blog
│   │   └── [slug]/
│   │       └── page.tsx # /blog/:slug
│   └── api/
│       └── hello/
│           └── route.ts # API: /api/hello
├── components/
├── public/
└── package.json