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