Skip to content

React Router

React Router enables client-side routing in React applications. That means your URL can change and React can render a different component without a full page reload.

graph LR A["URL changes"] --> B["Router matches path"] B --> C["Component tree updates"] C --> D["No full page reload"]

Without Router

URL change usually triggers a full page reload and server request.

With React Router

URL change updates only the relevant React components.

Install the package:

Terminal window
npm install react-router-dom

Wrap your app:

import { BrowserRouter } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Main />
</BrowserRouter>
);
}
import { Routes, Route } from "react-router-dom";
function Main() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
{/* Nested Route / Child Routes */}
<Route path="/user" element={<UserLayout />}>
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
);
}
FeatureJSX RoutesObject Routes
ReadabilityEasyModerate
ScalabilityMediumHigh
Dynamic configHardEasy
Used in large appsLessMore

Link handles navigation without reloading the page.

import { Link } from "react-router-dom";
<Link to="/about">Go to About</Link>;

NavLink is similar to Link, but it also knows whether the route is active.

import { NavLink } from "react-router-dom";
<NavLink to="/about">About</NavLink>;
FeatureLinkNavLink
NavigationYesYes
Active stylingNoYes
Use caseBasic navigationNavbar and menus
<NavLink to="/about" className={({ isActive }) => (isActive ? "active" : "")]}>
About
</NavLink>
.active {
color: red;
font-weight: bold;
}
graph LR A["Current URL"] --> B{"Matches NavLink path?"} B -- "Yes" --> C["isActive = true"] B -- "No" --> D["isActive = false"]

Dynamic routes help render pages like user profiles and products.

/users/1
/users/2
/users/3

Define dynamic route:

<Route path="/user/:id" element={<User />} />

Meaning:

:id = dynamic variable

Access dynamic parameter:

import { useParams } from "react-router-dom";
function User() {
const { id } = useParams();
return <h1>User ID: {id}</h1>;
}
graph TD A["URL: /user/10"] --> B["useParams()"] B --> C["{ id: '10' }"]

Route:

<Route path="/user/:id" element={<User />} />

Component:

import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
function User() {
const { id } = useParams();
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`https://api.example.com/users/${id}`)
.then((res) => res.json())
.then((data) => setUser(data));
}, [id]);
if (!user) return <p>Loading...</p>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
<Route path="/user" element={<UserLayout />}>
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>

Use useNavigate when navigation should happen from code (for example after form submit).

import { useNavigate } from "react-router-dom";
const navigate = useNavigate();
navigate("/about");

React Router uses a path matching algorithm.

/user/:id matches:
/user/1
/user/abc
graph TD A["User clicks Link"] --> B["URL changes"] B --> C["Router matches route"] C --> D["Component renders"] D --> E["useParams extracts values"] E --> F["API fetch if needed"] F --> G["UI updates"]
useEffect(() => {
fetchData();
}, []); // Wrong when id is used inside

Correct:

useEffect(() => {
fetchData(id);
}, [id]);
  • Routing is state: URL can be treated as application state.
  • Component tree changes based on URL.
  • Dynamic routing enables profile pages, product pages, and dashboards.
graph TD APP["/app"] --> HOME["Home"] APP --> USERS["Users"] USERS --> DETAIL["UserDetail (/user/:id)"]