If you’re building a React app, chances are you’ll need navigation. You want users to move between different pages (like Home, About, Dashboard) without reloading the browser. That’s where React Router comes in.
In this blog, we’ll cover everything you need to know about React Router: declarative routing, nested routes, dynamic routing, route guards, and even code splitting for performance.
1. Declarative Routing → BrowserRouter, Routes, Route
Definition:
React Router provides declarative routing, meaning we describe what routes should exist, and React Router handles the navigation for us.
Key Components:
BrowserRouter→ wraps the app and keeps UI in sync with the browser’s URL.Routes→ container for route definitions.Route→ defines which component to render for a specific path.
Example:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
👉 Here, when you visit /, Home is rendered. When you visit /about, About is rendered.
2. Nested Routes → The Outlet Pattern
Definition:
Nested routes allow us to render child routes inside parent routes. This is useful for dashboards, layouts, or multi-step forms.
Explanation:
React Router provides the Outlet component to show nested content.
Example:
import { BrowserRouter, Routes, Route, Outlet, Link } from "react-router-dom";
function DashboardLayout() {
return (
<div>
<h2>Dashboard</h2>
<nav>
<Link to="profile">Profile</Link> |
<Link to="settings">Settings</Link>
</nav>
<Outlet /> {/* Child routes appear here */}
</div>
);
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/dashboard" element={<DashboardLayout />}>
<Route path="profile" element={<h3>Profile Page</h3>} />
<Route path="settings" element={<h3>Settings Page</h3>} />
</Route>
</Routes>
</BrowserRouter>
);
}
👉 Visiting /dashboard/profile renders the DashboardLayout plus the Profile page inside the Outlet.
3. Dynamic Routing → useParams, useNavigate
Definition:
Dynamic routes let us create paths that depend on parameters (like /user/1, /user/2).
useParams: Reads URL parameters.
useNavigate: Programmatically navigates to a route.
Example:
import { BrowserRouter, Routes, Route, useParams, useNavigate } from "react-router-dom";
function User() {
const { id } = useParams();
const navigate = useNavigate();
return (
<div>
<h2>User ID: {id}</h2>
<button onClick={() => navigate("/")}>Go Home</button>
</div>
);
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/user/:id" element={<User />} />
</Routes>
</BrowserRouter>
);
}
👉 Visiting /user/42 will render User ID: 42.
4. Route Guards & Redirects → Authentication Checks
Definition:
Sometimes, we need to restrict access to certain routes (like /dashboard) unless the user is logged in. This is called a route guard.
Explanation:
We can build a PrivateRoute component that checks authentication.
Example:
import { Navigate } from "react-router-dom";
function PrivateRoute({ children }) {
const isAuthenticated = false; // Imagine checking user auth here
return isAuthenticated ? children : <Navigate to="/login" />;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/dashboard" element={<PrivateRoute><h2>Dashboard</h2></PrivateRoute>} />
<Route path="/login" element={<h2>Login Page</h2>} />
</Routes>
</BrowserRouter>
);
}
👉 If isAuthenticated is false, users are redirected to /login.
5. Code Splitting with Lazy Routes → React.lazy + Suspense
Definition:
Instead of loading all components at once, we can lazy-load them when needed. This improves performance, especially for large apps.
Explanation:
React provides React.lazy and Suspense to load components on demand.
Example:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import React, { Suspense, lazy } from "react";
const Home = lazy(() => import("./pages/Home"));
const About = lazy(() => import("./pages/About"));
function App() {
return (
<BrowserRouter>
<Suspense fallback={<h2>Loading...</h2>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
👉 Now, About is loaded only when the user visits /about.
🎯 Final Thoughts
- Declarative Routing: Define routes with
BrowserRouter,Routes,Route. - Nested Routes: Use
Outletfor layouts and dashboards. - Dynamic Routing: Access params with
useParams, navigate withuseNavigate. - Route Guards: Protect routes with custom components and redirects.
- Code Splitting: Optimize performance with
React.lazyandSuspense.
🚀 With these patterns, you can build scalable, secure, and performant navigation in React apps.
BrowserRouter → Routes → Outlet → Component
Comments
Post a Comment