I've written a breadcrumbs component (RouteBreadcrumbs
) that has the following features/behavior:
- Takes in an array of labels for each breadcrumb (ex:
['Settings', 'System settings', 'Display']
. The component displays these labels in the order that they're placed in in the array. - Assumes that the last label in the array represents the currently viewed page. For the rest of the labels that come before it, the user can click on one in order to navigate to that page.
- Gets the current path it is rendered in and parses it in order to assign the correct path for each breadcrumb (except the last one)
- If the current path does not contain enough "subpaths" to satisfy the number of labels passed in, I've chosen not to render the component. For example, the component would not render if the current path was only
/system-settings/display
whenlabels
contained three items.
Ultimately, the component would look like this when rendered (I haven't yet implemented the arrows between each breadcrumb):
Settings > System settings > Display
In this scenario, "Display" would be the currently viewed page. And the user would be able to click on "Settings" or "System settings" in order to jump to those respective pages.
I'd love to get feedback on my implementation. I'm also interested in learning more about best coding practices and whether there are any strong code smells in my component (and if there is one, why it is considered a code smell).
Some areas that I think might be code smells but am not really sure if they are or why they are:
- Calling
pathNameIdx--
both inside thewhile
loop and then again once the loop is exited - Having a
return
statement in multiple places in my component (in my case, in just two places) - Using a regular
for
loop instead of other forms likefor..of
,for..in
, or.forEach
.
import React from "react";
import { useHistory, useLocation } from "react-router-dom";
const RouteBreadcrumbs = ({labels = []}) => {
const location = useLocation();
const history = useHistory();
const pathName = location.pathname;
const numBackslash = (pathName.match(/\//g) || []).length;
if (numBackslash < labels.length) {
return null;
}
let breadcrumbPaths = [];
let pathNameIdx = pathName.length - 1;
for (let i = labels.length - 1; i > 0 ; i--) {
while ((pathName[pathNameIdx] !== "/")) {
console.assert(pathNameIdx >= 0, "pathNameIdx is no longer a valid index");
pathNameIdx--;
}
const newPath = pathName.substring(0, pathNameIdx);
breadcrumbPaths = [newPath, ...breadcrumbPaths];
pathNameIdx--;
}
return (
<div>
{labels.map((label, idx) => <h5 key={idx} onClick={idx < breadcrumbPaths.length ? () => history.push(breadcrumbPaths[idx]) : null} className={"label2"}>{label}</h5>)}
</div>
)
};
```