Reputation: 17858
I modified the sample given in React Router nested routing in the docs to setup nested routing in the base url, like this.
I want nested routing like /Home1
and /Home2
directly under the root url.
export default function NestingExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/topics">
<Topics />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
let { path, url } = useRouteMatch();
console.log({url, path});
return (
<div>
<h2>Homes</h2>
<ul>
<li>
<Link to="/home1">Home 1</Link>
{/* also tried <Link to={`${url}/home1`}>Home 1</Link> */}
</li>
<li>
<Link to="/home2">Home 2</Link>
</li>
</ul>
<Switch>
<Route exact path={path}>
<h3>Please select a home.</h3>
</Route>
<Route path={`${path}/home1`}>
<Home1 />
</Route>
<Route path={`${path}/home2`}>
<Home2 />
</Route>
</Switch>
</div>
);
}
function Home1() {
return (
<div>
<h3>Home1 Content</h3>
</div>
);
}
function Home2() {
return (
<div>
<h3>Home2 Content</h3>
</div>
);
}
No error displays in the browser, but Home1 page does not display. Isn't it possible to setup nested routing directly under the root?
Upvotes: 0
Views: 1829
Reputation: 938
You would need to reorder your routes so the base route is the last route within the stack(using the strict keyword)
eg.
<Switch>
<Route strict path="/users" component={UsersRoutes} />
<Route strict path="/" compoent={PublicRoutes} />
</Switch>
And with this, each page can render their own Not Found
pages.
eg.
// within PublicRoutes
<Switch>
<Route exact path={path} component={() => <h1>Public Page</h1>} />
<Route path="*" component={() => <h1>Not found</h1>} />
</Switch>
https://codesandbox.io/s/react-router-nesting-025cn?file=/example.js
Upvotes: 1
Reputation: 9
The problem is that react-router doesn't strip trailing slashes from path
and url
for you.
So at the root path: path === '/'
So when you concatenate that:
<Route exact path={`${path}/home1`}>
You end up with
<Route exact path="//home">
Which doesn't match any route
The easiest way to counter this is to normalize the path and url variables by removing the trailing slash
let { path, url } = useRouteMatch();
//strip trailing slashes
path = path.replace(/\/$/, '');
url = url.replace(/\/$/, '');
Your full example would be
export default function NestingExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<hr />
<Switch>
<Route path="/">
<Home />
</Route>
{/** Note That both "/" and "/home" will work */}
<Route path="/home">
<Home />
</Route>
<Route path="/topics">
<Topics />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
let { path, url } = useRouteMatch();
//strip trailing slashes
path = path.replace(/\/$/, '');
url = url.replace(/\/$/, '');
return (
<div>
<h2>Homes</h2>
<ul>
<li>
<Link to={`${url}/home1`}>Home 1</Link>
</li>
<li>
<Link to={`${url}/home2`}>Home 2</Link>
</li>
</ul>
<Switch>
<Route exact path={${path}/}>
<h3>Please select a home.</h3>
</Route>
<Route exact path={`${path}/home1`}>
<Home1 />
</Route>
<Route exact path={`${path}/home2`}>
<Home2 />
</Route>
</Switch>
</div>
);
}
function Home1() {
return (
<div>
<h3>Home1 Content</h3>
</div>
);
}
function Home2() {
return (
<div>
<h3>Home2 Content</h3>
</div>
);
}
Upvotes: 0
Reputation: 17858
I ended up creating a seperate /home
route, and redirected /
to /home
to be able to use nested routing inside the home.
But I am still interested in a more clever answer.
export default function NestingExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Redirect to="/home" />
</Route>
<Route path="/home">
<Home />
</Route>
<Route path="/topics">
<Topics />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
let { path, url } = useRouteMatch();
return (
<div>
<h2>Homes</h2>
<ul>
<li>
<Link to={`${url}/home1`}>Home 1</Link>
</li>
<li>
<Link to={`${url}/home2`}>Home 2</Link>
</li>
</ul>
<Switch>
<Route exact path={path}>
<h3>Please select a home.</h3>
</Route>
<Route path={`${path}/home1`}>
<Home1 />
</Route>
<Route path={`${path}/home2`}>
<Home2 />
</Route>
</Switch>
</div>
);
}
function Home1() {
return (
<div>
<h3>Home1 Content</h3>
</div>
);
}
function Home2() {
return (
<div>
<h3>Home2 Content</h3>
</div>
);
}
Upvotes: 0
Reputation: 3143
I did not try this, but my guess is by using the "exact" keyword in the route of your top router, the nested structure does not match the url anymore. If you remove the property, does it work?
More information: https://reacttraining.com/react-router/web/api/Route/exact-bool
Upvotes: 0