reactjsreact-router-dombreadcrumbs

In React Router 6, update router data after the route is rendered


In my application, I have a Breadcrumb component that uses the Router nested path to show the crumbs.

const matches = useMatches();

function createBreadcrumbList() {
  const breadcrumb = [];
  matches.forEach((route, index) => {
    const crumb = {};
    crumb.label = BREADCRUMB_PAGE_MAP[route.id];
    if (!crumb.label) return;

    if (matches.length - index > 1) crumb.to = route.pathname;
    breadcrumb.push(crumb);
  });

  return breadcrumb;
}

This creates a breadcrumb of this format,

Home > Users > User Info

The current setup works well for static values in the breadcrumb (Home, Users, etc). But I need a dynamic value present for the last route. For the User Info route I want to show the name of the user and a count.

Home > Users > Dennis (10)

screenshot

This data however is loaded dynamically after the route loads.

Is it possible to trigger an action that sets this data on the route and will cause the matches hook to run again?

Here is the Codesandbox link for this, https://codesandbox.io/s/router-breadcrumb-h6trtk


Solution

  • I wanted to retain my current code while implementing this requirement. I wanted a complete separation between the application code and breadcrumb functionality.

    The best way I found to update the data in the route, was to navigate to the same route once the data was ready and pass the data as a state object.

    useEffect(() => {
      if (posts.length > 0) {
        const postsStr = posts.length > 0 ? ` (${posts.length})` : "";
        navigate(location.pathname, {
          replace: true,
          state: { breadcrumb: { pageName: `${selectedUser?.name}${postsStr}` } }
        });
      }
    }, [posts]);
    

    In the breadcrumb I used this location object and used the saved value for the current route.

    export default function useBreadcrumb() {
      const matches = useMatches();
      const location = useLocation();
      ...
      ...
    
      let label = BREADCRUMB_PAGE_MAP[route.id];
      if (route.pathname === location.pathname) {
        label = location?.state?.breadcrumb?.pageName || label;
      }
      crumb.label = label;
    
      ...
      ...
    

    Here is the link to the fixed codesandbox,

    https://codesandbox.io/s/router-breadcrumb-fix-d4qv2w