Nested Routes with React Router V4/V5

Nested routes with react router v4 / v5

In react-router-v4 you don't nest <Routes />. Instead, you put them inside another <Component />.


For instance

<Route path='/topics' component={Topics}>
<Route path='/topics/:topicId' component={Topic} />
</Route>

should become

<Route path='/topics' component={Topics} />

with

const Topics = ({ match }) => (
<div>
<h2>Topics</h2>
<Link to={`${match.url}/exampleTopicId`}>
Example topic
</Link>
<Route path={`${match.path}/:topicId`} component={Topic}/>
</div>
)

Here is a basic example straight from the react-router documentation.

I need a nested route in react router V5

Within the Switch component path order and specificity matters! You want to order the routes from more specific paths to less specific paths. In this case you are rendering the "/access" path prior to any of the sub-route "/access/***" paths, so it is matched and rendered instead of the one really matching the path in the URL.

To fix, move the "/access" route config below the more specific routes.

export const ROUTES = [
// move "/access" route from here
{
name: "addTeam",
path: "/access/add-team",
component: lazy(() => import("./AddTeam"))
},
{
name: "addUser",
path: "/access/add-user",
component: lazy(() => import("./AddUser"))
},
// to here
{
name: "access",
path: "/access",
component: lazy(() => import("./Access"))
},
{
name: "admin",
path: "/admin",
component: lazy(() => import("./Admin"))
}
];

Sample Image

react-router v5 – nested routes

Apart from typo that you pointed out for declaring to instead of path

You can wrap Dashboard component Routes in a Switch

const Dashboard = (props) => (
<div className={styles.views}>
<Switch>
<Route
path="/dashboard/reports/create"
render={() => <ReportsForm {...props} />}
exact
/>
<Route
path="/dashboard/reports"
render={() => <Reports {...props} />}
exact
/>
</Switch>
</div>
);

If that dont work you can even wrap the entire thing in Route with initial path as follows:

const Dashboard = props => (
<div className={styles.views}>
<Route path="/dashboard/reports"> // <------------------
<Switch>
<Route path="/dashboard/reports/create" render={() => <ReportsForm {...props} />} exact />
<Route path="/dashboard/reports" render={() => <Reports {...props} />} exact />
</Switch>
</Route>
</div>
);

Here's the working example solution that I just created: https://stackblitz.com/edit/react-uih91e-router-nested?file=index.js

is it ok to use React Router Nested routes

These are descendent routes, not nested routes, but that doesn't matter as the question, as posed, is a bit subjective. react-router-dom allows it, so yes, it's ok to do. There is no issue with React components rendering descendent routes.

This is a very common routing pattern in RRDv4/5. RRDv6 allows it and made nesting routes even easier than in previous versions.

I'm not sure where exactly you were looking for examples of rendering descendent/"nested" routes and not finding any, but there's an official Nesting Example in the v5 docs.

React Router v5 - element under nested route not displaying

You appear to be mixing RRDv5 and RRDv6 component API/syntax. If using RRDv5 the descendent route rendered by HeatMapContainer should render content on the component prop (or render or children function props) instead of a non-existent element prop.

<Switch>
<Route path="/table" component={TablePage} />
<Route path="/heatmap" component={HeatMapContainer} />
<Route path="/" exact component={LandingPage} />
<Route component={NotFoundPage} />
</Switch>

HeatMapContainer

<div style={{ display: 'flex', justifyContent: 'center', width: '100%' }}>
HEAT MAP CONTAINER
<Link to="/heatmap/all">All</Link>
<Route path="/heatmap/all" component={AllOfficesRoute} />
</div>

React Router v5.0 Nested Routes

It took me some time to find the answer that I favoured.
Both @johnny-peter & @gaurab-kc solutions were great and they tought me about React's routing mechanism.

@johnny-peter 's solution had disadvantage of forcing me to put a prefix for all auth related routes under /auth/... (e.g. /auth/login & auth/sign-up) which I didn't wanted.

@gaurab-kc solution was supporting only one set of routes.. so if user was already signed up, he couldn't visit the /login route anymore.

Up till recently I used my own solution which had the problem of "defeating the whole purpose of a common header and footer." as @johnny-peter mentioned and it was down-voted few times as it should be.

Now I'm using another solution:

<Router history={browserHistory}>
<Switch>
<Redirect exact from="/" to="/home"/>
<Route exact path={["/login", "/sign-up", ...]}>
<AuthLayout>
<Switch>
<Route
path="/login"
component={LoginPage}
/>
<Route
path="/sign-up"
component={SignUpPage}
/>
</Switch>
</AuthLayout>
</Route>
<Route exact path={[
"/home",
"/dashboard",
...
]}>
<SiteLayout>
<Switch>
<Route
path="/home"
component={HomePage}
/>
<Route
path="/dashboard"
component={DashboardPage}
/>
</Switch>
</SiteLayout>
</Route>
<Route path="*" component={NotFoundPage}/>
</Switch>
</Router>

which prevents all the above disadventages. It's allows me to:

  1. Use a layout for each section which isn't re-rendered on route change.
  2. Doesn't forcing me to add any prefix to routes.
  3. All routes are working at the same time, letting users to route back into the /login or other auth routes without logout first.

The only disadvantage of this solution is having more code and duplicating the routes, but it's a cost I'm willing to pay.

Nested routing using protected routes is not working properly

I don't really know what ProtectRouteProps is and what I should put in it.

There are no props. This is clear by the usage:

<Route path='/createItem' element={<ProtectRoute />} />

No props are passed to ProtectRoute. You can drop the props object:

import { Navigate, Outlet } from "react-router";
import { RootStateOrAny, useSelector } from "react-redux";

export default function ProtectRoute() {
const userSignin = useSelector((state: RootStateOrAny) => state.userSignin);
const { userInfo } = userSignin;

return userInfo?.user?.isAdmin ? <Outlet /> : <Navigate to='/' replace />;
}

The problem now is that can't access CreateItem because is going on
the ProtectRoute page that is an empty one. What should i do?

"Auth" routes are what are called layout routes. They apply some logic, perhaps some styled layout CSS, and render an Outlet for nested Route components to be rendered into. The nested Route components use the path prop for route matching.

Example:

<Route element={<ProtectRoute />}>
<Route path='/createItem' element={<CreateItem />} />
... other protected routes ...
</Route>


Related Topics



Leave a reply



Submit