實作範例

  • 最終程式

    // NextBreadcrumbs.js
     
    const _defaultGetTextGenerator = (param, query) => null;
    const _defaultGetDefaultTextGenerator = path => path;
     
    // Pulled out the path part breakdown because its
    // going to be used by both `asPath` and `pathname`
    const generatePathParts = pathStr => {
      const pathWithoutQuery = pathStr.split("?")[0];
      return pathWithoutQuery.split("/")
                             .filter(v => v.length > 0);
    }
     
    export default function NextBreadcrumbs({
      getTextGenerator=_defaultGetTextGenerator,
      getDefaultTextGenerator=_defaultGetDefaultTextGenerator
    }) {
      const router = useRouter();
     
      const breadcrumbs = React.useMemo(function generateBreadcrumbs() {
        const asPathNestedRoutes = generatePathParts(router.asPath);
        const pathnameNestedRoutes = generatePathParts(router.pathname);
     
        const crumblist = asPathNestedRoutes.map((subpath, idx) => {
          // Pull out and convert "[post_id]" into "post_id"
          const param = pathnameNestedRoutes[idx].replace("[", "").replace("]", "");
     
          const href = "/" + asPathNestedRoutes.slice(0, idx + 1).join("/");
          return {
            href, textGenerator: getTextGenerator(param, router.query),
            text: getDefaultTextGenerator(subpath, href)
          }; 
        })
     
        return [{ href: "/", text: "Home" }, ...crumblist];
      }, [router.asPath, router.pathname, router.query, getTextGenerator, getDefaultTextGenerator]);
     
      return (
        <Breadcrumbs aria-label="breadcrumb">
          {breadcrumbs.map((crumb, idx) => (
            <Crumb {...crumb} key={idx} last={idx === breadcrumbs.length - 1} />
          ))}
        </Breadcrumbs>
      );
    }
     
     
    function Crumb({ text: defaultText, textGenerator, href, last=false }) {
     
      const [text, setText] = React.useState(defaultText);
     
      useEffect(async () => {
        // If `textGenerator` is nonexistent, then don't do anything
        if (!Boolean(textGenerator)) { return; }
        // Run the text generator and set the text again
        const finalText = await textGenerator();
        setText(finalText);
      }, [textGenerator]);
     
      if (last) {
        return <Typography color="text.primary">{text}</Typography>
      }
     
      return (
        <Link underline="hover" color="inherit" href={href}>
          {text}
        </Link>
      );
    }

Ref:

https://dev.to/dan_starner/building-dynamic-breadcrumbs-in-nextjs-17oa