nextjs-pathname-id-fetch について
Next.js 開発者向けに、動的ルートのパラメーターからページデータを取得する方法に絞ったスキルです。Server Component を保ち、Next.js 15+ では `params` を await する手順を示します。
主な機能
- 01角括弧付き動的ルートの作成
- 02params から識別子を取得
- 03パスパラメーターによるデータ取得
- 04ページを Server Component として維持
- 05パラメーターの明示的な型定義
活用シーン
- 01製品 ID に基づく詳細ページ表示
- 02slug に基づく記事コンテンツの取得
- 03管理パスの注文 ID によるデータ参照
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ wsimmonds/ claude-nextjs-skills --skill nextjs-pathname-id-fetchインストール後、Claude Code で/nextjs-pathname-id-fetchを入力して読み込まれたか確認します。
詳細
Next.js:パス名の ID に基づくデータ取得パターン
このパターンを使用する場面
URL に含まれる識別子に基づいてページのデータを読み込む必要がある場合は、このパターンを使用します。よくあるケースは次のとおりです。
- 商品、投稿、ユーザーの詳細ページ(
/products/{id}、/blog/{slug}) - 選択したリソースを掘り下げる管理ダッシュボード(
/admin/orders/{orderId}) - ネストしたパスを持つドキュメントやナレッジベース(
/docs/getting-started/installation)
現在の URL パスに応じてデータを変更する要件がある場合、ルートセグメントは動的にする必要があります(例:[id]、[slug]、[...slug])。
パターン
✅ 推奨される実装
1. Create a dynamic folder: app/[id]/page.tsx
2. Access the parameter: const { id } = await params;
3. Fetch data using that identifier
4. Render the requested information
❌ 落とし穴
Using app/page.tsx for this scenario prevents access to per-path identifiers.
実装例の全体
// app/[id]/page.tsx
// IMPORTANT: Server component (NO 'use client' needed!)
export default async function ProductPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
// Next.js 15+: params must be awaited
const { id } = await params;
// Fetch data using the ID from the URL
const response = await fetch(`https://api.example.com/products/${id}`);
const product = await response.json();
// Return JSX with the fetched data
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<p>Price: ${product.price}</p>
</div>
);
}
ファイル構成
app/
└── [id]/ ← Dynamic route folder with brackets
└── page.tsx ← Server component page
URL マッピング:
/123→ params ={ id: '123' }/abc→ params ={ id: 'abc' }/product-xyz→ params ={ id: 'product-xyz' }
主なルール
1. フォルダー名には必ず角括弧を使用する
✅ app/[id]/page.tsx
✅ app/[productId]/page.tsx
✅ app/[slug]/page.tsx
❌ app/id/page.tsx (no brackets = static route)
❌ app/page.tsx (can't access params here)
2. これはサーバーコンポーネントです(デフォルト)
// ✅ CORRECT - No 'use client' needed
export default async function Page({ params }) {
const { id } = await params;
const data = await fetch(`/api/${id}`);
return <div>{data.name}</div>;
}
// ❌ WRONG - Don't add 'use client' for server components
'use client'; // ← Remove this!
export default async function Page({ params }) { ... }
3. Params は await する必要があります(Next.js 15+)
// ✅ CORRECT - Next.js 15+
export default async function Page({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params; // Must await
// ...
}
// ⚠️ OLD (Next.js 14 and earlier - deprecated)
export default async function Page({
params,
}: {
params: { id: string };
}) {
const { id } = params; // No await needed in old versions
// ...
}
4. シンプルに保つ — ネストしすぎない
✅ app/[id]/page.tsx (simple, clean)
❌ app/products/[id]/page.tsx (only if explicitly required!)
要件で /products/[id] が明示的に求められていない限り、構成はトップレベル(app/[id]/page.tsx)に保ちます。
TypeScript:any 型は絶対に使用しない
このコードベースでは @typescript-eslint/no-explicit-any が有効になっています。any を使用するとビルドに失敗します。
// ❌ WRONG
function processProduct(product: any) { ... }
// ✅ CORRECT - Define proper types
interface Product {
id: string;
name: string;
price: number;
}
function processProduct(product: Product) { ... }
// ✅ ALSO CORRECT - Use unknown if type truly unknown
function processData(data: unknown) {
// Type guard required before using
if (typeof data === 'object' && data !== null) {
// ...
}
}
よくあるバリエーション
異なるパラメーター名
// app/[productId]/page.tsx
export default async function Page({
params,
}: {
params: Promise<{ productId: string }>;
}) {
const { productId } = await params;
// ...
}
// app/[slug]/page.tsx
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
// ...
}
複数のパラメーター
// app/[category]/[id]/page.tsx
export default async function Page({
params,
}: {
params: Promise<{ category: string; id: string }>;
}) {
const { category, id } = await params;
const data = await fetch(`/api/${category}/${id}`);
// ...
}
動作する実装例の全体
// app/[id]/page.tsx - Product detail page
interface Product {
id: string;
name: string;
description: string;
price: number;
inStock: boolean;
}
export default async function ProductPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
// Get the ID from the URL
const { id } = await params;
// Fetch product data using the ID
const response = await fetch(
`https://api.example.com/products/${id}`,
{ cache: 'no-store' } // Always fresh data
);
if (!response.ok) {
throw new Error('Failed to fetch product');
}
const product: Product = await response.json();
// Render the product
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<div>
<strong>Price:</strong> ${product.price}
</div>
<div>
<strong>Availability:</strong>{' '}
{product.inStock ? 'In Stock' : 'Out of Stock'}
</div>
</div>
);
}
簡単なチェックリスト
パス名に基づく詳細ページをリリースする前に、次の項目を確認してください。
- ルートフォルダー名に角括弧を使用している(例:
app/[id]/page.tsx) - コンポーネントがサーバー側にとどまっている(
'use client'は不要) - Next.js 15+ では
paramsプロパティの型をPromise<{ id: string }>にしている - params を await し、識別子を安全に読み取っている
- データ取得ロジックでその識別子を使用している
- レンダリングで読み込み中やエラーの状態を適切に処理している
- 型を明示している —
anyに頼らない
代わりに包括的なスキルを使用する場面
このマイクロスキルでは、シンプルな「パス名の ID に基づくデータ取得」パターンを扱います。次の場合は、包括的な nextjs-dynamic-routes-params スキルを使用してください。
- キャッチオールルート(
[...slug]) - オプショナルキャッチオールルート(
[[...slug]]) - 複雑な複数パラメーターのルーティング
- 高度なルーティングアーキテクチャ
- 詳細なルーティングの判断
「URL の ID でデータを取得する」というシンプルなケースであれば、このスキルだけで十分です。
コメント
Markdown 対応