You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现产品选择后跳转至单个产品页并获取对应产品数据

实现单个产品页获取选中产品数据的方案

基于你当前的Next.js项目结构和代码,以下两种常用方案可实现单个产品页获取对应产品数据:

方案一:组件内动态获取并筛选数据

适合需要实时拉取数据的场景,步骤如下:

  1. 引入依赖并复用类型定义
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';

// 复用主页面的产品类型接口
interface productItem {
  id: number;
  name: string;
  image: string;
  price?: string;
  prices: {
    half: string;
    full: string;
  };
  categories: string;
}
  1. 获取路由参数并匹配产品数据
const ProductDetail = () => {
  const router = useRouter();
  const { categories, id } = router.query;
  const [product, setProduct] = useState<productItem | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    // 路由参数存在时才发起请求
    if (categories && id) {
      const fetchProductDetail = async () => {
        try {
          const response = await fetch('/items.json');
          const productData = await response.json();
          
          // 根据分类匹配对应产品数组
          let targetProducts: productItem[] = [];
          switch(categories) {
            case 'Cake':
              targetProducts = productData.Cakes.map((item: productItem) => ({...item, categories: 'Cake'}));
              break;
            case 'Memorella':
              targetProducts = productData.Memorella.map((item: productItem) => ({...item, categories: 'Memorella'}));
              break;
            case 'Ice Cream':
              targetProducts = productData.Ice_Cream.map((item: productItem) => ({...item, categories: 'Ice Cream'}));
              break;
            case 'Pastries':
              targetProducts = productData.Pastries.map((item: productItem) => ({...item, categories: 'Pastries'}));
              break;
            default:
              throw new Error('无效的产品分类');
          }

          // 筛选出ID匹配的产品
          const matchedProduct = targetProducts.find(item => item.id === Number(id));
          matchedProduct ? setProduct(matchedProduct) : setError('未找到对应产品');
        } catch (err) {
          setError(err instanceof Error ? err.message : '获取产品数据失败');
        } finally {
          setLoading(false);
        }
      };

      fetchProductDetail();
    }
  }, [categories, id]);

  // 处理页面状态
  if (loading) return <div>加载产品中...</div>;
  if (error) return <div>错误:{error}</div>;
  if (!product) return <div>未找到产品</div>;

  // 渲染产品详情
  return (
    <div className="product-detail">
      <img src={product.image} alt={product.name} />
      <h1>{product.name}</h1>
      <div className="prices">
        <p>半份:₹{product.prices.half}</p>
        <p>整份:₹{product.prices.full}</p>
      </div>
    </div>
  );
};

export default ProductDetail;

方案二:Next.js静态生成(getStaticProps + getStaticPaths)

适用于产品数据稳定的场景,预生成所有产品页面以提升性能:

  1. 实现getStaticPaths定义预生成路由
    该函数告诉Next.js需要预生成哪些动态路由页面:
export async function getStaticPaths() {
  const response = await fetch('http://localhost:3000/items.json');
  const productData = await response.json();

  // 生成所有可能的产品路由路径
  const paths = [];
  
  Object.entries(productData).forEach(([key, items]) => {
    let categoryName = '';
    switch(key) {
      case 'Cakes':
        categoryName = 'Cake';
        break;
      case 'Memorella':
        categoryName = 'Memorella';
        break;
      case 'Ice_Cream':
        categoryName = 'Ice Cream';
        break;
      case 'Pastries':
        categoryName = 'Pastries';
        break;
    }
    (items as productItem[]).forEach(item => {
      paths.push({
        params: {
          categories: categoryName,
          id: item.id.toString()
        }
      });
    });
  });

  return {
    paths,
    fallback: false // 设为true时,未预生成的路径会在请求时动态生成
  };
}
  1. 实现getStaticProps获取对应产品数据
    构建阶段为每个预生成页面获取对应产品数据:
export async function getStaticProps({ params }: { params: { categories: string; id: string } }) {
  const { categories, id } = params;
  const response = await fetch('http://localhost:3000/items.json');
  const productData = await response.json();

  let targetProducts: productItem[] = [];
  switch(categories) {
    case 'Cake':
      targetProducts = productData.Cakes.map((item: productItem) => ({...item, categories: 'Cake'}));
      break;
    case 'Memorella':
      targetProducts = productData.Memorella.map((item: productItem) => ({...item, categories: 'Memorella'}));
      break;
    case 'Ice Cream':
      targetProducts = productData.Ice_Cream.map((item: productItem) => ({...item, categories: 'Ice Cream'}));
      break;
    case 'Pastries':
      targetProducts = productData.Pastries.map((item: productItem) => ({...item, categories: 'Pastries'}));
      break;
    default:
      throw new Error('无效的产品分类');
  }

  const product = targetProducts.find(item => item.id === Number(id));

  if (!product) {
    return { notFound: true }; // 返回404页面
  }

  return {
    props: { product }, // 传递给组件的属性
    revalidate: 86400 // 可选:每隔24小时重新生成页面(增量静态再生)
  };
}
  1. 组件接收属性并渲染
const ProductDetail = ({ product }: { product: productItem }) => {
  return (
    <div className="product-detail">
      <img src={product.image} alt={product.name} />
      <h1>{product.name}</h1>
      <div className="prices">
        <p>半份:₹{product.prices.half}</p>
        <p>整份:₹{product.prices.full}</p>
      </div>
    </div>
  );
};

export default ProductDetail;

注意事项

  • 确保items.json文件放在Next.js的public文件夹下,才能通过/items.json访问。
  • 生产环境中,方案一的fetch路径无需添加localhost,直接使用/items.json即可。
  • 数据频繁更新选方案一,数据稳定选方案二(性能更优)。

内容的提问来源于stack exchange,提问作者Dastagir Shaikh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 21:25:01