1. Next.js とは何ですか?
Next.js は実稼働用の React フレームワークであり、SSR、SSG、ファイルベースのルーティング、API ルート、その他多くのすぐに使用できる機能を提供します。ヴェルセル社が開発した。
| 特長 | 反応 (ヴァイト) | Next.js |
|---|---|---|
| レンダリング | クライアント側のみ | SSR、SSG、ISR、ストリーミング |
| ルーティング | React Router (マニュアル) | ファイルベース (組み込み) |
| SEO | 悪い (SPA) | 優秀(SSR/SSG) |
| API | 個別のバックエンド | ルート ハンドラー (組み込み) |
| 画像・フォント | 手動による最適化 | 次/画像、次/フォント |
| 導入 | 任意の静的ホスト | Vercel、Docker、任意の Node.js ホスト |
2. セットアップ
npx create-next-app@latest my-app --typescript --tailwind --app --src-dir
cd my-app
npm run dev
3. App Router — ファイルベースのルーティング
src/app/
├── layout.tsx ← Root layout (required)
├── page.tsx ← Home page (/)
├── loading.tsx ← Loading UI
├── error.tsx ← Error UI
├── not-found.tsx ← 404 page
├── globals.css
│
├── about/
│ └── page.tsx ← /about
│
├── blog/
│ ├── page.tsx ← /blog
│ └── [slug]/
│ └── page.tsx ← /blog/:slug (dynamic)
│
├── dashboard/
│ ├── layout.tsx ← Nested layout
│ ├── page.tsx ← /dashboard
│ ├── settings/
│ │ └── page.tsx ← /dashboard/settings
│ └── [...catchAll]/
│ └── page.tsx ← /dashboard/anything/else
│
└── (marketing)/ ← Route group (no URL segment)
├── layout.tsx
├── pricing/
│ └── page.tsx ← /pricing
└── features/
└── page.tsx ← /features
4. レイアウト
// src/app/layout.tsx — Root Layout
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
export const metadata: Metadata = {
title: { default: 'My App', template: '%s | My App' },
description: 'My awesome Next.js application',
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="vi">
<body className={inter.className}>
<Header />
<main>{children}</main>
<Footer />
</body>
</html>
);
}
// src/app/dashboard/layout.tsx — Nested Layout
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex">
<Sidebar />
<div className="flex-1">{children}</div>
</div>
);
}
5. ページ
// src/app/page.tsx — Home page
export default function HomePage() {
return <h1>Welcome to My App</h1>;
}
// src/app/blog/[slug]/page.tsx — Dynamic route
interface Props {
params: Promise<{ slug: string }>;
}
export default async function BlogPost({ params }: Props) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) notFound(); // → not-found.tsx
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}
// Generate static params for SSG
export async function generateStaticParams() {
const posts = await getAllPosts();
return posts.map(post => ({ slug: post.slug }));
}
6. 読み込みとエラー UI
// src/app/dashboard/loading.tsx
export default function Loading() {
return <div className="animate-pulse">Loading dashboard...</div>;
}
// src/app/dashboard/error.tsx
'use client'; // Error components must be Client Components
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error(error);
}, [error]);
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={reset}>Try again</button>
</div>
);
}
7. ナビゲーション
import Link from 'next/link';
import { useRouter, usePathname } from 'next/navigation';
// Link component (prefetching built-in)
<Link href="/about">About</Link>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
<Link href="/dashboard" prefetch={false}>Dashboard</Link>
// Programmatic navigation
'use client';
function SearchForm() {
const router = useRouter();
const pathname = usePathname();
const handleSubmit = (query: string) => {
router.push(`/search?q=${query}`);
// router.replace('/dashboard'); // Replace history
// router.back(); // Go back
// router.refresh(); // Re-fetch server components
};
}
次の記事: サーバーコンポーネントとクライアントコンポーネント — RSC、「クライアントの使用」、境界、および構成パターン。