mcpField
N
nextjs-pathname-id-fetch

nextjs-pathname-id-fetch

github.com/wsimmonds开发109295 次安装53 周前更新
代码仓库

关于 nextjs-pathname-id-fetch

面向 Next.js 开发者的路径标识符取数技能,聚焦于通过动态路由参数获取页面数据。它强调使用服务端组件、在 Next.js 15+ 等待 params,并保持路由结构简洁。

主要功能

  1. 01创建带括号的动态路由段
  2. 02从 params 读取标识符
  3. 03依据路径参数获取数据
  4. 04使用服务端组件处理页面
  5. 05为参数定义明确类型

适用场景

  1. 01按产品 ID 加载详情页
  2. 02按文章 slug 获取内容
  3. 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(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 并安全地读取标识符
  • 数据获取逻辑使用该标识符
  • 渲染逻辑适当地处理加载和错误状态
  • 类型明确——绝不退而使用 any

何时改用完整技能

此微技能介绍了简单的“按路径名 ID 获取数据”模式。以下情况请使用完整的 nextjs-dynamic-routes-params 技能:

  • 捕获所有路由([...slug])
  • 可选捕获所有路由([[...slug]])
  • 复杂的多参数路由
  • 高级路由架构
  • 详细的路由决策

对于“按 URL 中的 ID 获取数据”这一简单场景,此技能已足够。

评论

支持 Markdown