nextjs-pathname-id-fetch by wsimmonds/claude-nextjs-skills
npx skills add https://github.com/wsimmonds/claude-nextjs-skills --skill nextjs-pathname-id-fetch当页面需要根据 URL 中出现的标识符加载数据时,请使用此模式。常见场景包括:
/products/{id}、/blog/{slug})/admin/orders/{orderId})/docs/getting-started/installation)如果需求说明数据应根据当前 URL 路径变化,则路由段必须是动态的(例如 [id]、[slug]、[...slug])。
✅ 推荐实现
app/[id]/page.tsx广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
const { id } = await params;❌ 常见陷阱
在此场景中使用 app/page.tsx 会阻止访问每个路径的标识符。
// app/[id]/page.tsx
// 重要:服务器组件(不需要 'use client'!)
export default async function ProductPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
// Next.js 15+:必须 await params
const { id } = await params;
// 使用 URL 中的 ID 获取数据
const response = await fetch(`https://api.example.com/products/${id}`);
const product = await response.json();
// 返回包含获取数据的 JSX
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<p>Price: ${product.price}</p>
</div>
);
}
app/
└── [id]/ ← 带括号的动态路由文件夹
└── page.tsx ← 服务器组件页面
URL 映射:
/123 → params = { id: '123' }/abc → params = { id: 'abc' }/product-xyz → params = { id: 'product-xyz' }✅ app/[id]/page.tsx
✅ app/[productId]/page.tsx
✅ app/[slug]/page.tsx
❌ app/id/page.tsx (无括号 = 静态路由)
❌ app/page.tsx (此处无法访问 params)
// ✅ 正确 - 不需要 'use client'
export default async function Page({ params }) {
const { id } = await params;
const data = await fetch(`/api/${id}`);
return <div>{data.name}</div>;
}
// ❌ 错误 - 不要为服务器组件添加 'use client'
'use client'; // ← 移除这个!
export default async function Page({ params }) { ... }
// ✅ 正确 - Next.js 15+
export default async function Page({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params; // 必须 await
// ...
}
// ⚠️ 旧版(Next.js 14 及更早版本 - 已弃用)
export default async function Page({
params,
}: {
params: { id: string };
}) {
const { id } = params; // 旧版本中不需要 await
// ...
}
✅ app/[id]/page.tsx (简单,清晰)
❌ app/products/[id]/page.tsx (仅在明确要求时使用!)
除非需求明确要求 /products/[id],否则请将结构保持在顶层(app/[id]/page.tsx)。
any 类型此代码库已启用 @typescript-eslint/no-explicit-any。使用 any 将导致构建失败。
// ❌ 错误
function processProduct(product: any) { ... }
// ✅ 正确 - 定义适当的类型
interface Product {
id: string;
name: string;
price: number;
}
function processProduct(product: Product) { ... }
// ✅ 也正确 - 如果类型确实未知,请使用 unknown
function processData(data: unknown) {
// 在使用前需要类型守卫
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 - 产品详情页面
interface Product {
id: string;
name: string;
description: string;
price: number;
inStock: boolean;
}
export default async function ProductPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
// 从 URL 获取 ID
const { id } = await params;
// 使用 ID 获取产品数据
const response = await fetch(
`https://api.example.com/products/${id}`,
{ cache: 'no-store' } // 始终获取最新数据
);
if (!response.ok) {
throw new Error('Failed to fetch product');
}
const product: Product = await response.json();
// 渲染产品信息
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<div>
<strong>价格:</strong> ${product.price}
</div>
<div>
<strong>库存状态:</strong>{' '}
{product.inStock ? '有货' : '缺货'}
</div>
</div>
);
}
在发布由路径名驱动的详情页面之前,请确认:
app/[id]/page.tsx)'use client')params 属性被类型化为 Promise<{ id: string }>any此微技能涵盖了简单的“路径名 ID 获取”模式。对于以下情况,请使用综合技能 nextjs-dynamic-routes-params:
[...slug])[[...slug]])对于“从 URL 按 ID 获取数据”这种简单情况,此技能就是您所需要的。
每周安装量
108
代码仓库
GitHub 星标数
80
首次出现
2026 年 1 月 23 日
安全审计
安装于
claude-code88
opencode86
codex84
gemini-cli81
github-copilot81
cursor81
Use this pattern whenever a page needs to load data based on whatever identifier appears in the URL. Common scenarios include:
/products/{id}, /blog/{slug})/admin/orders/{orderId})/docs/getting-started/installation)If the requirement says the data should change depending on the current URL path, the route segment must be dynamic (e.g., [id], [slug], [...slug]).
✅ Recommended implementation
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
❌ Pitfall
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 Mapping:
/123 → params = { id: '123' }/abc → params = { id: 'abc' }/product-xyz → params = { id: 'product-xyz' }✅ 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)
// ✅ 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 }) { ... }
// ✅ 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
// ...
}
✅ app/[id]/page.tsx (simple, clean)
❌ app/products/[id]/page.tsx (only if explicitly required!)
Unless requirements explicitly call for /products/[id], keep the structure at the top level (app/[id]/page.tsx).
any TypeThis codebase has @typescript-eslint/no-explicit-any enabled. Using any will cause build failures.
// ❌ 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>
);
}
Before shipping a pathname-driven detail page, confirm:
app/[id]/page.tsx)'use client' needed)params prop is typed as Promise<{ id: string }> for Next.js 15+anyThis micro-skill covers the simple "pathname ID fetch" pattern. Use the comprehensive nextjs-dynamic-routes-params skill for:
[...slug])[[...slug]])For the simple case of "fetch data by ID from URL", this skill is all you need.
Weekly Installs
108
Repository
GitHub Stars
80
First Seen
Jan 23, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
claude-code88
opencode86
codex84
gemini-cli81
github-copilot81
cursor81
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
118,000 周安装
system-info 系统信息技能 | 获取操作系统、Python版本、目录列表的脚本工具
198 周安装
SEO内容审计工具 - 自动化内容质量分析、E-E-A-T评估与优化建议
198 周安装
MQL5指标开发实战模式:解决缓冲区、显示、实时更新等常见问题
197 周安装
Hyvä Playwright 测试指南:解决 Alpine.js 冲突,编写可靠电商自动化测试
195 周安装
TDD 工作流指南:红绿重构循环、三定律与实践原则 | 测试驱动开发
198 周安装
Visual Explainer - 技术图表与数据表格HTML生成器 | 自动可视化工具
197 周安装