Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Breadcrumbs and NextJS

I'd like to make a breadcrumb for my NextJS application, and I'd like to know if there is a good or practical way to do it?

I'd like to go through Ant Design, but the example of the component with React Router doesn't want to work for me.

I need your help please...

like image 496
jipay Avatar asked Oct 26 '20 16:10

jipay


3 Answers

If you are using the Next.js routing system I suggest you have a look at nextjs-breadcrumbs, it is simple and effective.

Or if you prefer to write your own component use their code as reference.

import React, { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import Link from 'next/link';

const convertBreadcrumb = string => {
  return string
    .replace(/-/g, ' ')
    .replace(/oe/g, 'ö')
    .replace(/ae/g, 'ä')
    .replace(/ue/g, 'ü')
    .toUpperCase();
};

const Breadcrumbs = () => {
  const router = useRouter();
  const [breadcrumbs, setBreadcrumbs] = useState(null);

  useEffect(() => {
    if (router) {
      const linkPath = router.asPath.split('/');
      linkPath.shift();

      const pathArray = linkPath.map((path, i) => {
        return { breadcrumb: path, href: '/' + linkPath.slice(0, i + 1).join('/') };
      });

      setBreadcrumbs(pathArray);
    }
  }, [router]);

  if (!breadcrumbs) {
    return null;
  }

  return (
    <nav aria-label="breadcrumbs">
      <ol className="breadcrumb">
        <li>
          <a href="/">HOME</a>
        </li>
        {breadcrumbs.map((breadcrumb, i) => {
          return (
            <li key={breadcrumb.href}>
              <Link href={breadcrumb.href}>
                <a>
                  {convertBreadcrumb(breadcrumb.breadcrumb)}
                </a>
              </Link>
            </li>
          );
        })}
      </ol>
    </nav>
  );
};

export default Breadcrumbs;
like image 80
Mark Nunes Avatar answered Sep 20 '22 23:09

Mark Nunes


This my approach to bread crumbs in nextjs, it uses the router.asPath to get the link to the crumb and the router.route to get the label if it exists in the Route2LabelMap.

pages/example.jsx

export default function Page() {
  return <>
    <BreadCrumbs />
    <h1>My Page</h1>
  </>
}

components/BreadCrumbs.jsx

import Link from "next/link";
import { useRouter } from "next/router";
import React from "react";

/*
interface BreadCrumb {
  route: string;
  label: string;
  link: string;
}
*/

const Route2LabelMap = {
  "/": "Home",
  "/profile/[username]/barrels": "Your Barrels",
  "/barrels": "Barrel List",
  "/barrels/[barrel_id]": "Barrel",
  "/barrels/[barrel_id]/settings": "Settings",
};

export function BreadCrumbs() {
  const router = useRouter();

  const [crumbs, setCrumbs] = React.useState([]);

  React.useEffect(() => {
    const segmentsPath = router.asPath.split("/");
    const segmentsRoute = router.route.split("/");
    const crumbLinks = CombineAccumulatively(segmentsPath);
    const crumbLabels = CombineAccumulatively(segmentsRoute);

    const crumbs = crumbLinks.map((link, index) => {
      const route = crumbLabels[index];
      const crumb = {
        link: link,
        route: route,
        label: Route2LabelMap[route] || route,
      };
      return crumb;
    });
    setCrumbs(crumbs);

    console.log({
      router,
      segmentsPath,
      segmentsRoute,
      crumbLinks,
      crumbLabels,
      crumbs,
    });
  }, [router.route]);

  return (
    <div className="w-full flex gap-1">
      {crumbs.map((c, i) => {
        return (
          <div className="flex items-center gap-1" key={i}>
            {(i > 0) ? <div>{'>'}</div> : null}
            <div className={(i == (crumbs.length - 1) ? 'bg-blue-300 ' : 'bg-gray-300 ') + " px-2 py-1 rounded-xl"}>
              <Link href={c.link}>
                <a>{c.label}</a>
              </Link>
            </div>
          </div>
        );
      })}
    </div>
  );
}

function CombineAccumulatively(segments) {
  /* 
  when segments = ['1','2','3']
  returns ['1','1/2','1/2/3']
  */
  const links = segments.reduce((acc, cur, curIndex) => {
    const last = curIndex > 1 ? acc[curIndex - 1] : "";
    const newPath = last + "/" + cur;
    acc.push(newPath);
    return acc;
  }, []);
  return links;
}

Rendered BreadCrumbs

In this case, either the route is shown, or the label is shown if it exists in the Route2LabelMap variable, like "Your Barrels" does.

enter image description here

like image 34
Ben Winding Avatar answered Sep 20 '22 23:09

Ben Winding


    const router = useRouter()
    const linkPath = router.asPath.split('/');
    linkPath.shift();

    const pathArray = linkPath.map((path, i) => {
        return { breadcrumb: path, href: '/' + linkPath.slice(0, i + 1).join('/') };
    });
    console.log(pathArray)
like image 45
illia chill Avatar answered Sep 19 '22 23:09

illia chill