nextjs について
nextjsは、Next.jsでモダンなWebアプリを開発するためのスキルです。App Routerを使う開発者向けに、コンポーネント、データ取得、Server Actions、APIルート、ミドルウェアを扱います。
主な機能
- 01App Routerのページとレイアウト
- 02サーバー・クライアントコンポーネント
- 03データ取得とキャッシュ再検証
- 04Server ActionsとAPIルート
- 05ミドルウェアと環境変数の管理
活用シーン
- 01ローディング・エラー状態を備えたページの構築
- 02サーバーでのデータ取得とキャッシュ
- 03Server Actionsによるデータ更新
- 04ルートへの認証チェックとレスポンスヘッダー追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ thelobbi/ claude --skill nextjsインストール後、Claude Code で/nextjsを入力して読み込まれたか確認します。
詳細
Next.js スキル
モダンなウェブアプリケーション向けに、包括的な Next.js 開発機能を提供します。
このスキルを使用するタイミング
以下の作業を行う際に、このスキルを有効にします。
- Next.js App Router
- サーバーコンポーネントとクライアントコンポーネント
- API ルートとサーバーアクション
- 静的サイト生成(SSG)
- サーバーサイドレンダリング(SSR)
プロジェクト構成(App Router)
``` app/ ├── layout.tsx # ルートレイアウト ├── page.tsx # ホームページ ├── loading.tsx # 読み込み UI ├── error.tsx # エラー処理 ├── not-found.tsx # 404 ページ ├── globals.css ├── agents/ │ ├── page.tsx # /agents │ ├── [id]/ │ │ ├── page.tsx # /agents/[id] │ │ └── edit/ │ │ └── page.tsx # /agents/[id]/edit │ └── new/ │ └── page.tsx # /agents/new ├── api/ │ └── agents/ │ ├── route.ts # /api/agents │ └── [id]/ │ └── route.ts # /api/agents/[id] └── (dashboard)/ # ルートグループ ├── layout.tsx └── settings/ └── page.tsx ```
サーバーコンポーネント(デフォルト)
```tsx // app/agents/page.tsx - サーバーコンポーネント async function AgentsPage() { // データベースに直接アクセス(API は不要) const agents = await db.query('SELECT * FROM agents');
return (
エージェント
-
{agents.map(agent => (
- {agent.name} ))}
export default AgentsPage; ```
クライアントコンポーネント
```tsx // components/AgentSelector.tsx 'use client';
import { useState } from 'react';
export function AgentSelector({ agents }: { agents: Agent[] }) { const [selected, setSelected] = useState<string | null>(null);
return ( <select value={selected || ''} onChange={(e) => setSelected(e.target.value)} > エージェントを選択 {agents.map(agent => ( {agent.name} ))} ); } ```
データの取得
サーバーコンポーネントでのデータ取得
```tsx
// リクエストの自動重複排除
async function getAgent(id: string) {
const res = await fetch(${process.env.API_URL}/agents/${id}, {
cache: 'force-cache', // デフォルト:無期限でキャッシュ
// cache: 'no-store', // キャッシュしない
// next: { revalidate: 60 } // 60 秒ごとに再検証
});
return res.json();
}
export default async function AgentPage({ params }: { params: { id: string } }) { const agent = await getAgent(params.id); return ; } ```
再検証
```tsx // 時間ベースの再検証 export const revalidate = 60; // 60 秒ごとに再検証
// オンデマンド再検証 import { revalidatePath, revalidateTag } from 'next/cache';
async function updateAgent(id: string, data: FormData) { 'use server'; await db.update('agents', id, data); revalidatePath('/agents'); revalidateTag('agents'); } ```
サーバーアクション
```tsx // app/agents/new/page.tsx import { redirect } from 'next/navigation';
async function createAgent(formData: FormData) { 'use server';
const name = formData.get('name') as string; const type = formData.get('type') as string;
await db.insert('agents', { name, type });
revalidatePath('/agents'); redirect('/agents'); }
export default function NewAgentPage() { return (
Claude GPT エージェントを作成 ); } ```API ルート
```tsx // app/api/agents/route.ts import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams; const type = searchParams.get('type');
const agents = await db.query( 'SELECT * FROM agents WHERE type = $1', [type] );
return NextResponse.json(agents); }
export async function POST(request: NextRequest) { const body = await request.json();
const agent = await db.insert('agents', body);
return NextResponse.json(agent, { status: 201 }); }
// app/api/agents/[id]/route.ts export async function GET( request: NextRequest, { params }: { params: { id: string } } ) { const agent = await db.query('SELECT * FROM agents WHERE id = $1', [params.id]);
if (!agent) { return NextResponse.json({ error: 'Not found' }, { status: 404 }); }
return NextResponse.json(agent); } ```
レイアウトと読み込み状態
```tsx // app/layout.tsx export default function RootLayout({ children, }: { children: React.ReactNode; }) { return (
ナビゲーション {children} フッター ); }// app/agents/loading.tsx export default function Loading() { return
// app/agents/error.tsx 'use client';
export default function Error({ error, reset, }: { error: Error; reset: () => void; }) { return (
問題が発生しました!
<button onClick={() => reset()}>もう一度試すミドルウェア
```tsx // middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) { // 認証チェック const token = request.cookies.get('token');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) { return NextResponse.redirect(new URL('/login', request.url)); }
// ヘッダーを追加 const response = NextResponse.next(); response.headers.set('x-custom-header', 'value');
return response; }
export const config = { matcher: ['/dashboard/:path*', '/api/:path*'], }; ```
環境変数
```bash
.env.local
DATABASE_URL=postgresql://... API_URL=http://localhost:8000
公開用(ブラウザーに公開)
NEXT_PUBLIC_APP_URL=http://localhost:3000 ```
```tsx // サーバー専用 const dbUrl = process.env.DATABASE_URL;
// クライアントからアクセス可能 const appUrl = process.env.NEXT_PUBLIC_APP_URL; ```
ビルドコマンド
```bash
開発
npm run dev
本番ビルド
npm run build npm start
静的エクスポート
npm run build
next.config.js: output: 'export'
```