Nested Routes, Route Params, and Navigation (Deep Dive)

Modern React applications are rarely flat. As soon as your project scales beyond a handful of pages or features like dashboards, user profiles, and detail pages, you need to structure your routes thoughtfully. This module covers nested routes, dynamic route parameters, and advanced navigation patterns in React Router v6, giving you architectural clarity and full control over your page transitions.


1. What Are Nested Routes? Why Are They Important?

❖ Nested Routes = Layout Reuse

Nested routes allow you to render child routes within a shared layout, without duplicating the layout code across each route.

❖ Nested Routes = Cleaner URLs

Instead of flat routes like /dashboard-settings, you can organize routes hierarchically:

  • /dashboard
  • /dashboard/settings
  • /dashboard/profile

❖ Nested Routes = Component Composition

React Router v6 embraces the component tree by matching it to the route tree, enabling composition at both layout and logic levels.


2. Creating Nested Routes in React Router v6

Let’s build a nested dashboard.

Routes Setup

import { Routes, Route } from 'react-router-dom';
import Dashboard from './pages/Dashboard';
import Profile from './pages/Profile';
import Settings from './pages/Settings';

export default function AppRoutes() {
return (
<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
);
}

Dashboard Layout with <Outlet />

In Dashboard.jsx:

import { Outlet } from 'react-router-dom';

export default function Dashboard() {
return (
<div>
<h1>Dashboard Layout</h1>
<nav>
<Link to="profile">Profile</Link>
<Link to="settings">Settings</Link>
</nav>
<section>
<Outlet /> {/* Renders Profile or Settings here */}
</section>
</div>
);
}

Key points:

  • The Outlet component is where child routes will be rendered.
  • The path inside children is relative, i.e., profile is treated as /dashboard/profile.

3. Using Index Routes for Defaults

React Router allows index routes for rendering a default component when a parent path is matched.

<Route path="/dashboard" element={<Dashboard />}>
<Route index element={<Welcome />} />
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>

When users visit /dashboard, the Welcome component renders by default.


4. Route Parameters: Dynamic Routing Made Simple

What Are Route Params?

Route parameters capture dynamic values from the URL.

<Route path="/users/:userId" element={<UserProfile />} />
  • /users/42 will render UserProfile with userId = 42

Accessing Parameters

import { useParams } from 'react-router-dom';

const UserProfile = () => {
const { userId } = useParams(); // { userId: '42' }
return <div>User ID: {userId}</div>;
};

You can have multiple params like /teams/:teamId/members/:memberId.


5. Nested Dynamic Routes

You can even nest dynamic segments:

<Route path="/products/:productId" element={<ProductLayout />}>
<Route path="reviews" element={<ProductReviews />} />
<Route path="specs" element={<ProductSpecs />} />
</Route>

Access both productId and the child routes via useParams() in child components.


6. Navigation Techniques

React Router offers declarative and programmatic navigation methods.

a. <Link /> Component

<Link to="/dashboard/profile">Profile</Link>
<Link to="settings">Settings</Link> {/* relative to current route */}

b. useNavigate() Hook

import { useNavigate } from 'react-router-dom';

const SubmitButton = () => {
const navigate = useNavigate();

const handleSubmit = () => {
// Do something
navigate('/dashboard');
};

return <button onClick={handleSubmit}>Submit</button>;
};

c. Navigating With State

You can pass additional data:

navigate('/checkout', { state: { total: 999 } });

Retrieve it in the destination component:

const { state } = useLocation();
console.log(state.total);

7. Wildcard & Fallback Routes

For 404 pages or catching all unmatched routes:

<Route path="*" element={<NotFound />} />

For nested wildcards:

<Route path="docs/*" element={<Documentation />} />

The * matches any path after /docs.


8. Shared Layout Pattern (Reusable Containers)

Use a Layout.jsx to apply shared navigation, headers, or sidebars:

<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="contact" element={<Contact />} />
</Route>

In Layout.jsx:

<>
<Header />
<main>
<Outlet />
</main>
<Footer />
</>

9. Structuring Routes in Larger Applications

Organize routes in files:

src/
routes/
index.jsx
dashboardRoutes.jsx
authRoutes.jsx

Inside dashboardRoutes.jsx:

export default [
{
path: 'overview',
element: <Overview />
},
{
path: 'settings',
element: <Settings />
}
];

This modular approach improves maintainability.


10. Performance Optimization with Lazy Loading

import { lazy, Suspense } from 'react';

const Settings = lazy(() => import('./pages/Settings'));

<Route path="settings" element={
<Suspense fallback={<Loading />}>
<Settings />
</Suspense>
} />

This reduces initial bundle size and improves perceived performance.


11. Relative Links and Deep Routing UX

When inside a nested route like /dashboard/profile, use relative paths:

<Link to="settings">Go to Settings</Link> // resolves to /dashboard/settings

Or for parent path:

<Link to="..">Back to Dashboard</Link> // resolves one level up

React Router v6 handles relative paths much more intuitively.


Conclusion

Nested routes, route parameters, and flexible navigation patterns are foundational for creating sophisticated, scalable React applications. Understanding how to build layout-aware routing, manage dynamic segments, and navigate with both user interaction and programmatically gives you full control over your app’s structure and flow.