React Router - Navigation in React Apps
What is Client-Side Routing?
When you navigate between pages on a traditional website, the browser makes a new HTTP request and the server sends back a new HTML page. This causes a full page reload.
Client-side routing lets a single-page application (SPA) update the URL and render different content without ever leaving the page or making a full page reload. The result is a fast, app-like navigation experience.
React Router is the most popular library for client-side routing in React applications.
Setting Up React Router
In a Vite React project, install React Router with:
npm install react-router-dom
Then wrap your application in BrowserRouter:
// main.jsx
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import ReactDOM from "react-dom/client";
ReactDOM.createRoot(document.getElementById("root")).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
Defining Routes
Use Routes and Route to define which component renders for each URL path:
// App.jsx
import { Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import Courses from "./pages/Courses";
import CourseDetail from "./pages/CourseDetail";
import NotFound from "./pages/NotFound";
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/courses" element={<Courses />} />
<Route path="/courses/:id" element={<CourseDetail />} />
<Route path="*" element={<NotFound />} />
</Routes>
);
}
The * path is a catch-all that renders the 404 page for any unmatched URL.
Navigation with Link
Use the <Link> component instead of <a href="..."> to navigate without a page reload:
import { Link } from "react-router-dom";
function Navbar() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/courses">Courses</Link>
<Link to="/about">About</Link>
</nav>
);
}
NavLink — Active Styling
NavLink is like Link but adds an active class automatically when its to matches the current URL:
import { NavLink } from "react-router-dom";
function Navbar() {
return (
<nav>
<NavLink to="/" end className={({ isActive }) => isActive ? "nav-link active" : "nav-link"}>
Home
</NavLink>
<NavLink to="/courses" className={({ isActive }) => isActive ? "nav-link active" : "nav-link"}>
Courses
</NavLink>
</nav>
);
}
URL Parameters with useParams
Dynamic route segments use : as a prefix. Extract them with the useParams hook:
import { useParams } from "react-router-dom";
// Route: <Route path="/courses/:courseId" element={<CourseDetail />} />
function CourseDetail() {
const { courseId } = useParams();
return <h1>Course ID: {courseId}</h1>;
}
Programmatic Navigation with useNavigate
useNavigate lets you navigate from JavaScript code, such as after a form submission:
import { useNavigate } from "react-router-dom";
function LoginPage() {
const navigate = useNavigate();
async function handleLogin(e) {
e.preventDefault();
await loginUser(); // Your login logic
navigate("/dashboard"); // Redirect after login
}
return <form onSubmit={handleLogin}>...</form>;
}
// Navigate back
navigate(-1); // Goes to the previous page in history
Nested Routes
React Router supports nested routes for shared layouts:
import { Outlet } from "react-router-dom";
function CoursesLayout() {
return (
<div>
<h1>Courses</h1>
<nav>
<Link to="html">HTML</Link>
<Link to="css">CSS</Link>
</nav>
<Outlet /> {/* Renders the matched child route here */}
</div>
);
}
// In your routes:
<Route path="/courses" element={<CoursesLayout />}>
<Route index element={<CoursesList />} /> {/* /courses */}
<Route path="html" element={<HtmlCourse />} /> {/* /courses/html */}
<Route path="css" element={<CssCourse />} /> {/* /courses/css */}
</Route>
Key Takeaways
- Client-side routing updates the URL and renders new content without a full page reload, creating fast SPA navigation
- Wrap your app in BrowserRouter to enable React Router
- Define URL-to-component mappings with Routes and Route; use * as a catch-all for 404 pages
- Use Link (not anchor tags) to navigate between routes; NavLink adds active styling automatically
- Extract URL parameters like /courses/:id using the useParams hook
- Navigate programmatically (after form submission, login, etc.) using the useNavigate hook
Practice Exercise
- Set up React Router in a Vite project with these routes: Home (/), About (/about), Courses (/courses), and Course Detail (/courses/:id)
- Create a shared Navbar using NavLink with active styling for each route
- On the Courses page, render a list of 3 courses. Each course name should be a Link to /courses/1, /courses/2, and /courses/3
- On the Course Detail page, use useParams to get the ID and display "Showing details for course ID: X"
- Add a 404 page using the * path
Try it yourself
Key Takeaways
- Client-side routing updates the URL and renders new content without a full page reload, creating a fast SPA experience
- Wrap your app root in BrowserRouter to enable React Router; define routes with Routes and Route
- Use Link (or NavLink) instead of anchor tags to navigate between routes without triggering a page reload
- Dynamic URL segments (:id) are extracted with the useParams hook: const { id } = useParams()
- useNavigate returns a function for programmatic navigation — useful for redirecting after form submissions or authentication
- Nested routes use Outlet to render child route components inside a shared parent layout
Quick Quiz
1.What is the difference between <a href> and <Link to> in React Router?
2.What does the * path in a Route mean?
3.How do you access the :courseId parameter from the URL /courses/42?
4.What does Outlet render in a nested route setup?
Ready to go further?
CareerEx gives you structured 12-week training, live classes every Saturday and Sunday, real tutor feedback, and a certificate. Join the next cohort.
Join CareerEx