使用 next js 设置动态路由

问题描述 投票:0回答:2

我正在尝试构建一个 Next.js 应用程序来显示按类别和子类别组织的产品目录。类别和子类别数据存储在一个对象数组中,如下所示:

const categories = [
  {
    id: 1,
    name: "Category A",
    subcategories: [
      {
        id: 1,
        name: "Subcategory A1",
        subsubcategories: [
          {
            id: 1,
            name: "Sub-Subcategory A1.1",
          },
          {
            id: 2,
            name: "Sub-Subcategory A1.2",
          },
        ],
      },
      {
        id: 2,
        name: "Subcategory A2",
        subsubcategories: [
          {
            id: 3,
            name: "Sub-Subcategory A2.1",
          },
          {
            id: 4,
            name: "Sub-Subcategory A2.2",
          },
        ],
      },
    ],
  },
  {
    id: 2,
    name: "Category B",
    subcategories: [
      {
        id: 3,
        name: "Subcategory B1",
        subsubcategories: [
          {
            id: 5,
            name: "Sub-Subcategory B1.1",
          },
          {
            id: 6,
            name: "Sub-Subcategory B1.2",
          },
        ],
      },
      {
        id: 4,
        name: "Subcategory B2",
        subsubcategories: [
          {
            id: 7,
            name: "Sub-Subcategory B2.1",
          },
          {
            id: 8,
            name: "Sub-Subcategory B2.2",
          },
        ],
      },
    ],
  },
];

我希望能够为遵循模式类别/子类别/子子类别/产品 ID 的每个产品生成动态路径。例如,如果用户单击类别 A、子类别 A1 和子子类别 A1.1 中 ID 为 123 的产品,则 URL 应如下所示:/category-a/subcategory-a1/sub-subcategory-a1- 1/123.

产品数据存储在一个单独的对象数组中,如下所示:

const products = [
  {
    id: 123,
    name: "Product A1.1.1",
    category_id: 1,
    subcategory_id: 1,
    subsubcategory_id: 1,
    description: "Lorem ipsum dolor sit amet",
    price: 9.99,
    image: "/images/product-a1-1-1.jpg",
  },]

category-a/subcategory-a1/sub-subcategory-a1-1/123.

next.js next nextjs13 dynamic-routing nextjs-dynamic-routing
2个回答
1
投票

试试这个:

// 文件:

/pages/[category]/[subcategory]/[subsubcategory]/[product].js

import React from 'react'
import { useRouter } from 'next/router'

    const items = [
      {
        id: 1,
        name: "Banana",
        category: 1,
        subcategory: 1,
        subsubcategory: 1,
      },
      {
        id: 2,
        name: "Foobar",
        category: 2,
        subcategory: 3,
        subsubcategory: 5,
      }
    ];
    
    
    const categories = [
      {
        id: 1,
        name: "Fruits",
        subcategories: [
          {
            id: 1,
            name: "Tropical fruits",
            subsubcategories: [
              {
                id: 1,
                name: "Berry fruits", // yes a banana is really a berry fruit
              },
              {
                id: 2,
                name: "Sub-Subcategory A1.2",
              },
            ],
          },
          {
            id: 2,
            name: "Subcategory A2",
            subsubcategories: [
              {
                id: 3,
                name: "Sub-Subcategory A2.1",
              },
              {
                id: 4,
                name: "Sub-Subcategory A2.2",
              },
            ],
          },
        ],
      },
      {
        id: 2,
        name: "Category B",
        subcategories: [
          {
            id: 3,
            name: "Subcategory B1",
            subsubcategories: [
              {
                id: 5,
                name: "Sub-Subcategory B1.1",
              },
              {
                id: 6,
                name: "Sub-Subcategory B1.2",
              },
            ],
          },
          {
            id: 4,
            name: "Subcategory B2",
            subsubcategories: [
              {
                id: 7,
                name: "Sub-Subcategory B2.1",
              },
              {
                id: 8,
                name: "Sub-Subcategory B2.2",
              },
            ],
          },
        ],
      },
    ];
    
    const slugify = str =>
      str
        .toLowerCase()
        .trim()
        .replace(/[^\w\s-]/g, '')
        .replace(/[\s_-]+/g, '-')
        .replace(/^-+|-+$/g, '');
    
    export default function Product() {
    
      const router = useRouter()
    
      const { category, subcategory, subsubcategory, product } = router.query
      console.log(category, subcategory, subsubcategory, product);
      // {category: 'fruits', subcategory: 'tropical-fruits', subsubcategory: 'berry-fruits', product: 'banana'}
    
    
      const found = items.find((item) => slugify(item.name) === product); // banana === banana
      console.log({ found });
      // {id: 1, name: 'Banana', category: 1, subcategory: 1, subsubcategory: 1}
    
      return (
        <div>{found.name}</div>
      )
    }
    
    export async function getStaticPaths() {
    
      const paths = items.map((item) => {
        // find the right categories for this product item
        let categoryFound = categories.find((c) => c.id == item.category);
        let subcategoryFound = categoryFound.subcategories.find((sc) => sc.id == item.subcategory);
        let subsubcategoryFound = subcategoryFound.subsubcategories.find((ssc) => ssc.id == item.subsubcategory);
    
        return {
          params: {
            product: slugify(item.name), // the slug
            category: slugify(categoryFound.name),
            subcategory: slugify(subcategoryFound.name),
            subsubcategory: slugify(subsubcategoryFound.name)
          }
        }
      });
    
      return {
        paths,
        fallback: false,
      };
    
    }
    
    export async function getStaticProps({ params }) {
    
      const { category, subcategory, subsubcategory, product } = params;
    
      return {
        props: {
          category,
          subcategory,
          subsubcategory,
          product,
        },
      };
    }

构建过程还构建了具有正确类别的产品页面: 图片

你可以像这样打开你的产品:

http://localhost:3000/fruits/tropical-fruits/berry-fruits/banana

1
投票

基本理念:

  1. 在 NextJs 构建之前生成

    pages/
    app/
    页面(准备脚本)

  2. 想太多的嵌套结构:subsubsub 没那么通用,万一哪天多出 3 个子类呢?无论如何,你保存一些代码并使用递归使其更具可读性......

顺便说一句,我想我要给 NextJS 准备提案,它真的有点缺失.. 页面应该像那样生成。

// Proposal: consider this article structure… dev’s love flattened structures
const articles = [
  id: 1,
  name: “banana”,
  category: [1, 1, 1]
];

// some pseudo code to let you start already. BTW just call them ‘categories’ in nesting if possible. ask backend, otherwise map it yourself (use a generator function instead of map if many articles to avoid memory overconsumption) I dislike the fact that category and subCategory can have same id, id’s should be unique in the whole app, hard to get a category/subcategory by id otherwise (or redundant code and complications on later usecases. should still work having `id: 1` everywhere:
const categories = [
  id: 1,
  name: “fruits”,
  categories: [
    {
      id: 1,
      name: “berry fruits”,
      categories: [
         {
            id: 1,
            name: “small berries lol” // 🍓🫐
         }
      ]
    }
  ]
];

// get paths to generate (deepest nesting)
function recursive(category, currentPath=“”){
  return category.categories
    ? recursive(category.categories,`$(currentPath}/[${category.name}]`)
    : category(`${currentPath}/[${category.name}]/`;
});

const paths = recursive(categories);
});

// create dynamic folder structure
// could be done in ‘recursive else’ too (faster)
paths.forEach((path) => {
  mkdirp.sync(path); // install 📦 first
});

// then articles…

// I am writing all of this on my mobile device, will enhance later, hope you get an idea of the approach I’m suggesting meanwhile

让我知道你在做什么,将在真实设备上继续 😉

currentPath的参数有一个错误,稍后编辑

© www.soinside.com 2019 - 2024. All rights reserved.