I am trying to implement React Router Breadcrumbs for v4
Following are my routes:
const routes = {
'/': 'Home',
'/page1': 'Page 1',
'/page2': 'Page 2'
};
I could put the breadcrumbs using this library in my application, however I am having following questions:
Que. #1:
When I click on Home
in my breadcrumbs, I can see the URL changes to http://localhost:8080
However, browser still shows the same page I am on.
Que. #2:
When I navigate to Page2 from Page1, url
changes from http://localhost:8080/page1
to http://localhost:8080/page2
.
So the breadcrumbs shown changes to Home / Page 2
instead of changing like Home / Page 1 / Page 2
I know this may be because the url
just has /page2
after hostname. But, can I achieve the display like: Home / Page 1 / Page 2
?
Below is the code in my main App.jsx
:
<Router>
<div>
<Link to="/"><div className="routerStyle"><Glyphicon glyph="home" /></div></Link>
<Route exact path="/" component={LandingPage}/>
<Route path="/page1" component={Page1}/>
<Route path="/page2" component={Page2}/>
</div>
</Router>
and if I use like belowto cater for breadcrumbs, then my page2 gets rendered below page1 stuff:
<Router>
<div>
<Link to="/"><div className="routerStyle"><Glyphicon glyph="home" /></div></Link>
<Route exact path="/" component={LandingPage}/>
<Route path="/page1" component={Page1}/>
<Route path="/page1/page2" component={Page2}/>
</div>
</Router>
Answer:
Que. #1: No need to wrap <Breadcrumbs ..../>
element inside <Router>
element inside each Component of application. This may be because, inclusion of <Router>
element inside each Component leads to "nesting" of Router
elements (note we have Router
tag in landing page as well); which does not work with react router v4
.
Que. #2: Refer to answer formally marked here (answered by palsrealm below)
Your breadcrumbs are based on links and they work as designed. To display the pages, you need to set up a Switch
with Route
s in it which would load the appropriate components when the path changes. Something like
<Switch>
<Route path='/' component={Home}/>
<Route path='/page1' component={Page1}/>
<Route path='/page2' component={Page2}/>
</Switch>
If you want the breadcrumb to show Home/Page1/Page2
your routes
should be '/page1/page2' : 'Page 2'
. The Route
should also change accordingly.
Edit: Your Router
should be
<Router>
<div>
<Link to="/"><div className="routerStyle"><Glyphicon glyph="home" /></div></Link>
<Switch>
<Route exact path="/" component={LandingPage}/>
<Route exact path="/page1" component={Page1}/>
<Route path="/page1/page2" component={Page2}/>
</Switch>
</div>
</Router>
This can also be accomplished with a HOC which would allow you to use a route config object to set breadcrumbs instead. I've open-sourced it here , but the source code is below as well:
Breadcrumbs.jsx
import React from 'react';
import { NavLink } from 'react-router-dom';
import { withBreadcrumbs } from 'withBreadcrumbs';
const UserBreadcrumb = ({ match }) =>
<span>{match.params.userId}</span>; // use match param userId to fetch/display user name
const routes = [
{ path: 'users', breadcrumb: 'Users' },
{ path: 'users/:userId', breadcrumb: UserBreadcrumb},
{ path: 'something-else', breadcrumb: ':)' },
];
const Breadcrumbs = ({ breadcrumbs }) => (
<div>
{breadcrumbs.map(({ breadcrumb, path, match }) => (
<span key={path}>
<NavLink to={match.url}>
{breadcrumb}
</NavLink>
<span>/</span>
</span>
))}
</div>
);
export default withBreadcrumbs(routes)(Breadcrumbs);
withBreadcrumbs.js
import React from 'react';
import { matchPath, withRouter } from 'react-router';
const renderer = ({ breadcrumb, match }) => {
if (typeof breadcrumb === 'function') { return breadcrumb({ match }); }
return breadcrumb;
};
export const getBreadcrumbs = ({ routes, pathname }) => {
const matches = [];
pathname
.replace(/\/$/, '')
.split('/')
.reduce((previous, current) => {
const pathSection = `${previous}/${current}`;
let breadcrumbMatch;
routes.some(({ breadcrumb, path }) => {
const match = matchPath(pathSection, { exact: true, path });
if (match) {
breadcrumbMatch = {
breadcrumb: renderer({ breadcrumb, match }),
path,
match,
};
return true;
}
return false;
});
if (breadcrumbMatch) {
matches.push(breadcrumbMatch);
}
return pathSection;
});
return matches;
};
export const withBreadcrumbs = routes => Component => withRouter(props => (
<Component
{...props}
breadcrumbs={
getBreadcrumbs({
pathname: props.location.pathname,
routes,
})
}
/>
));
The following component should return a breadcrumb at any depth, except on the home page (for obvious reasons). You won't need React Router Breadcrumb . My first public contribution, so if I'm missing an essential part, it would be great if somebody could point it out. I added »
for crumbs splits, but you can obviously update that to match what you need.
import React from 'react'
import ReactDOM from 'react-dom'
import { Route, Link } from 'react-router-dom'
// styles
require('./styles/_breadcrumbs.scss')
// replace underscores with spaces in path names
const formatLeafName = leaf => leaf.replace('_', ' ')
// create a path based on the leaf position in the branch
const formatPath = (branch, index) => branch.slice(0, index + 1).join('/')
// output the individual breadcrumb links
const BreadCrumb = props => {
const { leaf, index, branch } = props,
leafPath = formatPath(branch, index),
leafName = index == 0 ? 'home' : formatLeafName(leaf),
leafItem =
index + 1 < branch.length
? <li className="breadcrumbs__crumb">
<Link to={leafPath}>{leafName}</Link>
<span className="separator">»</span>
</li>
: <li className="breadcrumbs__crumb">{leafName}</li>
// the slug doesn't need a link or a separator, so we output just the leaf name
return leafItem
}
const BreadCrumbList = props => {
const path = props.match.url,
listItems =
// make sure we're not home (home return '/' on url)
path.length > 1
&& path
// create an array of leaf names
.split('/')
// send our new array to BreadCrumb for formating
.map((leaf, index, branch) =>
<BreadCrumb leaf={leaf} index={index} branch={branch} key={index} />
)
// listItem will exist anywhere but home
return listItems && <ul className="breadcrumbs">{listItems}</ul>
}
const BreadCrumbs = props =>
<Route path="/*" render={({ match }) => <BreadCrumbList match={match} />} />
export default BreadCrumbs
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.