1. What is React Router?
React Router is a library used to handle navigation and URLs in React applications.
For example, suppose you have a React application:
Home
Products
About
Contact
You may want URLs like:
/
/products
/about
/contact
React Router connects these URLs to React components.
For example:
URL React Component
/ Home
/products Products
/products/101 ProductDetails
/about About
/contact Contact
So when the user visits:
/products
React Router can render:
<Products />
instead of the Home component.
The important point is:
React Router allows a React application to behave like a multi-page application while still being a Single Page Application (SPA).
The browser URL changes, but React normally does not reload the entire HTML page.
2. Why Do We Need React Router?
Without React Router, you could manually check window.location.pathname.
For example:
const path = window.location.pathname;
if (path === "/") {
return <Home />;
}
if (path === "/products") {
return <Products />;
}
if (path === "/about") {
return <About />;
}
This works for a very small application, but becomes difficult to maintain.
Imagine an application with:
/
/products
/products/1
/products/2
/products/3
/cart
/checkout
/login
/register
/account
/account/profile
/account/orders
/admin
/admin/users
/admin/products
You don't want to manually manage all these routes.
React Router provides a structured routing system.
It gives you features such as:
- Route configuration
- Navigation
- Dynamic routes
- Nested routes
- Route parameters
- Query parameters
- Redirect/navigation
- Protected routes
- Layout routes
- Error routes
- 404 pages
- Lazy loading
- Data loading
- Form actions
- Navigation state
- Route-based code splitting
3. React Router and Single Page Applications
React applications are commonly built as Single Page Applications (SPAs).
Consider:
Browser
|
| https://example.com/products
|
React Application
|
+-- React Router
|
+-- /products
|
+-- Products component
When the user navigates from:
/products
to:
/about
React Router changes the URL and determines which React component should be displayed.
The browser does not normally download a completely new HTML document.
The flow is approximately:
User clicks link
|
v
React Router intercepts navigation
|
v
URL changes
|
v
Router matches URL
|
v
Matching React component renders
|
v
React updates the DOM
This is one of the main reasons React Router is useful.
4. Installing React Router
For modern React applications, install:
npm install react-router-dom
Then you can import routing functionality from:
import {
BrowserRouter,
Routes,
Route
} from "react-router-dom";
5. Basic React Router Example
Suppose you have:
src/
App.tsx
Home.tsx
About.tsx
Contact.tsx
Home.tsx
export default function Home() {
return <h1>Home Page</h1>;
}
About.tsx
export default function About() {
return <h1>About Page</h1>;
}
Contact.tsx
export default function Contact() {
return <h1>Contact Page</h1>;
}
Now configure the routes.
App.tsx
import {
BrowserRouter,
Routes,
Route
} from "react-router-dom";
import Home from "./Home";
import About from "./About";
import Contact from "./Contact";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
);
}
export default App;
Now:
http://localhost:5173/
renders:
Home Page
And:
http://localhost:5173/about
renders:
About Page
And:
http://localhost:5173/contact
renders:
Contact Page
6. BrowserRouter
BrowserRouter provides the routing context to your React application.
Example:
<BrowserRouter>
<App />
</BrowserRouter>
or, if routing is configured inside App:
function App() {
return (
<BrowserRouter>
<Routes>
...
</Routes>
</BrowserRouter>
);
}
React Router needs this context so that components can access routing functionality.
Without it, components using things such as:
<Link />
useNavigate()
useLocation()
useParams()
cannot work correctly.
A common architecture is:
main.tsx
|
v
BrowserRouter
|
v
App
|
+-- Routes
|
+-- Home
+-- Products
+-- About
7. Routes and Route
Two important components are:
<Routes>
and:
<Route />
Example:
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/products" element={<Products />} />
</Routes>
Think of it as:
URL Component
/ Home
/about About
/products Products
Routes manages the collection of routes.
Route defines an individual route.
8. Navigation Using Link
You should generally use React Router's Link instead of a normal HTML <a> element for internal application navigation.
Example:
import { Link } from "react-router-dom";
function Navbar() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/products">Products</Link>
</nav>
);
}
The user can click:
Home | About | Products
and React Router handles the navigation.
Why not <a href>?
You can write:
<a href="/products">Products</a>
but this can cause a normal browser navigation.
For internal SPA navigation, prefer:
<Link to="/products">
Products
</Link>
9. Link vs NavLink
Link is used for navigation.
NavLink is useful when you want to know whether the current route is active.
For example:
import { NavLink } from "react-router-dom";
<NavLink to="/products">
Products
</NavLink>
You can dynamically apply CSS:
<NavLink
to="/products"
className={({ isActive }) =>
isActive ? "active" : ""
}
>
Products
</NavLink>
If the current URL is:
/products
then:
isActive === true
This is particularly useful for:
- Navigation menus
- Sidebars
- Admin dashboards
- Tabs
- Breadcrumb navigation
10. Dynamic Routes
One of the most important features of React Router is the dynamic route.
Suppose you have products:
Product 101
Product 102
Product 103
You might want URLs:
/products/101
/products/102
/products/103
You don't want to create three separate routes.
Instead:
<Route
path="/products/:id"
element={<ProductDetails />}
/>
Here:
:id
is a route parameter.
11. Reading Route Parameters with useParams
Inside the component:
import { useParams } from "react-router-dom";
function ProductDetails() {
const { id } = useParams();
return (
<h1>
Product ID: {id}
</h1>
);
}
If the URL is:
/products/101
then:
id
contains:
101
If the URL is:
/products/500
then:
id
contains:
500
The flow is:
/products/101
|
v
React Router matches
|
v
/products/:id
|
v
id = "101"
|
v
ProductDetails
12. Real-World Dynamic Route Example
Suppose an API returns:
[
{
"id": 101,
"name": "Laptop"
},
{
"id": 102,
"name": "Keyboard"
}
]
Your product listing might contain:
<Link to={`/products/${product.id}`}>
{product.name}
</Link>
For Laptop:
/products/101
For Keyboard:
/products/102
Then:
function ProductDetails() {
const { id } = useParams();
// Fetch product using id
}
This is one of the most common real-world uses of React Router.
13. Route Parameters vs Query Parameters
This is an important interview topic.
Route parameter
/products/101
Route:
<Route
path="/products/:id"
element={<ProductDetails />}
/>
Used when the value identifies a specific resource.
For example:
/products/101
/users/50
/orders/9001
Query parameter
/products?category=laptop
Query parameters are usually used for filtering, searching, sorting, pagination, etc.
For example:
/products?category=laptop&page=2
Conceptually:
Path parameter
/products/101
|
+-- identifies product
Query parameter
/products?category=laptop
|
+-- filters products
14. Query Parameters with useSearchParams
React Router provides:
useSearchParams()
Example:
import {
useSearchParams
} from "react-router-dom";
function Products() {
const [searchParams, setSearchParams] =
useSearchParams();
const category =
searchParams.get("category");
return (
<div>
Category: {category}
</div>
);
}
For:
/products?category=laptop
the result is:
Category: laptop
15. Updating Query Parameters
You can change query parameters:
setSearchParams({
category: "laptop"
});
The URL becomes:
/products?category=laptop
You can also have:
setSearchParams({
category: "laptop",
page: "2"
});
Result:
/products?category=laptop&page=2
This is very useful for search pages.
16. Real-World Search Scenario
Imagine an e-commerce application.
User searches:
laptop
You could represent it as:
/products?search=laptop
User selects:
Electronics
and page 2:
/products?search=laptop&category=electronics&page=2
Now the URL itself represents the current search state.
This has a major advantage:
The user can copy the URL and share it with another person.
The other person can open the same URL and see the same search/filter state.
17. Programmatic Navigation with useNavigate
Sometimes navigation needs to happen from JavaScript rather than from a link.
React Router provides:
useNavigate()
Example:
import { useNavigate } from "react-router-dom";
function Login() {
const navigate = useNavigate();
function handleLogin() {
// login successful
navigate("/dashboard");
}
return (
<button onClick={handleLogin}>
Login
</button>
);
}
The flow is:
User clicks Login
|
v
Authentication succeeds
|
v
navigate("/dashboard")
|
v
URL changes
|
v
Dashboard renders
18. navigate with Browser History
You can navigate backward:
navigate(-1);
Forward:
navigate(1);
For example:
<button onClick={() => navigate(-1)}>
Back
</button>
This is useful when implementing custom navigation buttons.
19. Replace Navigation
Normally:
navigate("/dashboard");
adds a new browser history entry.
You can replace the current entry:
navigate("/dashboard", {
replace: true
});
This is useful for scenarios such as login redirects.
For example:
/login
|
| successful login
v
/dashboard
You may not want the user to press Back and return to /login.
Therefore:
navigate("/dashboard", {
replace: true
});
can be appropriate.
20. Nested Routes
Nested routing is extremely useful in real applications.
Consider an admin application:
/admin
/admin/users
/admin/products
/admin/settings
You could configure:
<Route path="/admin" element={<AdminLayout />}>
<Route path="users" element={<Users />} />
<Route path="products" element={<Products />} />
<Route path="settings" element={<Settings />} />
</Route>
This means:
/admin
|
+-- AdminLayout
|
+-- users
+-- products
+-- settings
21. Outlet
Nested routes normally use:
<Outlet />
inside the parent layout.
Example:
import { Outlet } from "react-router-dom";
function AdminLayout() {
return (
<div>
<h1>Admin Panel</h1>
<nav>
...
</nav>
<main>
<Outlet />
</main>
</div>
);
}
Now:
/admin/users
renders:
Admin Panel
Navigation
Users
And:
/admin/products
renders:
Admin Panel
Navigation
Products
The AdminLayout remains while the child route changes.
22. Why Outlet Is Important
Think of <Outlet /> as a placeholder for child routes.
For example:
<AdminLayout>
Header
Sidebar
<Outlet />
Footer
</AdminLayout>
If the current route is:
/admin/users
then <Outlet /> becomes:
<Users />
If the route is:
/admin/products
then <Outlet /> becomes:
<Products />
This is one of the most important concepts in React Router.
23. Layout Routes
A layout route lets multiple pages share the same UI.
For example:
Website
├── Header
├── Navigation
├── Main Content
└── Footer
You don't want to repeat the Header and Footer in every page.
Instead:
<Route element={<PublicLayout />}>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Route>
And:
function PublicLayout() {
return (
<>
<Header />
<main>
<Outlet />
</main>
<Footer />
</>
);
}
This creates a clean application structure.
24. Index Routes
Suppose you have:
/admin
/admin/users
/admin/products
You may want /admin to display a default page.
You can use:
<Route path="/admin" element={<AdminLayout />}>
<Route
index
element={<Dashboard />}
/>
<Route
path="users"
element={<Users />}
/>
<Route
path="products"
element={<Products />}
/>
</Route>
The index route represents the default child route.
Therefore:
/admin
renders:
Dashboard
25. 404 Not Found Route
A professional application should handle invalid URLs.
Example:
<Route
path="*"
element={<NotFound />}
/>
The * catches URLs that don't match your other routes.
For example:
/abcxyz
might display:
404
Page Not Found
A common pattern:
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/products" element={<Products />} />
<Route
path="*"
element={<NotFound />}
/>
</Routes>
26. Protected Routes
This is extremely common in real applications.
Suppose your application has:
/public
/login
/dashboard
/profile
/admin
Anyone can access:
/login
but only authenticated users should access:
/dashboard
/profile
A protected route checks authentication before rendering the protected page.
Conceptually:
User requests /dashboard
|
v
Is user authenticated?
/ \
Yes No
| |
v v
Dashboard Login
27. Simple Protected Route Example
Suppose:
function ProtectedRoute() {
const isAuthenticated =
localStorage.getItem("token");
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
}
Then configure:
<Route element={<ProtectedRoute />}>
<Route
path="/dashboard"
element={<Dashboard />}
/>
<Route
path="/profile"
element={<Profile />}
/>
</Route>
Now:
/dashboard
/profile
are protected.
28. Navigate vs Navigate Component
There are two related concepts.
useNavigate
Used inside JavaScript logic:
const navigate = useNavigate();
navigate("/dashboard");
<Navigate />
Used when rendering needs to redirect:
return <Navigate to="/login" replace />;
A useful way to remember:
useNavigate()
|
+-- imperative/programmatic navigation
<Navigate />
|
+-- navigation during rendering
29. Role-Based Routing
Authentication alone may not be enough.
Suppose you have:
Admin
Manager
Employee
And:
/admin
/manager
/employee
You may want to check the user's role.
For example:
function AdminRoute() {
const role = localStorage.getItem("role");
if (role !== "admin") {
return <Navigate to="/unauthorized" replace />;
}
return <Outlet />;
}
Then:
<Route element={<AdminRoute />}>
<Route
path="/admin"
element={<AdminDashboard />}
/>
</Route>
This creates role-based route protection.
30. Authentication vs Authorization
These concepts are often confused.
Authentication
Answers:
Who are you?
Example:
User has valid JWT token
Authorization
Answers:
What are you allowed to access?
Example:
User is authenticated
but does not have Admin role
Therefore:
Authentication
|
v
Is the user logged in?
|
v
Authorization
|
v
Does the user have permission?
React Router can help enforce frontend navigation rules, but real authorization must also be enforced by the backend/API.
Never rely only on React Router for security.
31. Child Route Parameters
You can combine nested routes and parameters.
Example:
<Route path="/users" element={<UsersLayout />}>
<Route
path=":userId"
element={<UserDetails />}
/>
</Route>
URL:
/users/101
Then:
const { userId } = useParams();
returns:
101
32. Multiple Route Parameters
You can have:
<Route
path="/users/:userId/orders/:orderId"
element={<OrderDetails />}
/>
URL:
/users/10/orders/500
Then:
const {
userId,
orderId
} = useParams();
Result:
userId = "10"
orderId = "500"
This is useful for hierarchical resources.
33. Optional Parameters and Modern Routing
Routing syntax can change between React Router versions, so avoid copying older tutorials blindly.
For current React Router projects, check the version documentation when using advanced route-pattern features.
For common applications, prefer clear routes such as:
/products
/products/:id
and query parameters such as:
/products?category=electronics
rather than making route patterns unnecessarily complex.
34. Relative Navigation
Nested routing supports relative paths.
Suppose the current route is:
/products/101
You can use:
<Link to="reviews">
Reviews
</Link>
which can resolve to:
/products/101/reviews
This is particularly useful with nested routes.
35. Absolute vs Relative Routes
Absolute
<Link to="/products">
Products
</Link>
Starts from the application root.
Relative
<Link to="reviews">
Reviews
</Link>
Resolves relative to the current route context.
Understanding this becomes important when working with nested routes.
36. Navigation State
Sometimes you want to send temporary data during navigation.
For example:
navigate("/product", {
state: {
productName: "Laptop"
}
});
The destination can read the state using:
const location = useLocation();
console.log(location.state);
This can be useful for UI navigation state.
However, don't treat navigation state as a replacement for persistent application data or URL parameters.
37. useLocation
useLocation() gives information about the current location.
Example:
const location = useLocation();
console.log(location.pathname);
console.log(location.search);
console.log(location.hash);
For:
/products?category=laptop#reviews
you can conceptually access:
pathname = /products
search = ?category=laptop
hash = #reviews
This is useful when your component needs to react to URL changes.
38. Example: Detecting URL Changes
const location = useLocation();
useEffect(() => {
console.log("URL changed:", location.pathname);
}, [location.pathname]);
This can be useful for:
- Analytics
- Page tracking
- UI behavior
- Route-specific logic
Be careful not to put unnecessary logic into global location listeners.
39. Route-Based Data Fetching
A very common real-world pattern is:
/products/101
|
v
useParams()
|
v
id = 101
|
v
API request
|
v
GET /api/products/101
|
v
Product data
|
v
Render ProductDetails
Example:
function ProductDetails() {
const { id } = useParams();
useEffect(() => {
fetch(`/api/products/${id}`)
.then(response => response.json())
.then(data => {
// update state
});
}, [id]);
return <div>Product Details</div>;
}
The important idea is that the route parameter drives the data request.
40. React Router with useState
React Router and useState often work together.
For example:
function Products() {
const [products, setProducts] = useState<Product[]>([]);
// fetch products
return (
...
);
}
The route determines which page is displayed, while state manages data and UI state inside that page.
Think:
React Router
|
+-- Which page?
|
v
Products component
|
+-- useState
|
+-- products
+-- loading
+-- selected filter
41. React Router with useEffect
A route parameter often becomes a dependency for useEffect.
const { id } = useParams();
useEffect(() => {
loadProduct(id);
}, [id]);
If the user changes:
/products/101
to:
/products/102
the component can react to the changed parameter and fetch the new product.
42. React Router with Context API
Suppose you have authentication information in Context:
<AuthContext>
The router can use authentication information from that context.
Conceptually:
AuthContext
|
+-- user
+-- token
+-- role
|
v
ProtectedRoute
|
v
React Router
|
v
Protected Pages
Example:
const { user } = useAuth();
if (!user) {
return <Navigate to="/login" replace />;
}
This is cleaner than repeatedly checking localStorage throughout the application.
43. React Router with Redux
React Router can also work with Redux.
For example:
Router
|
+-- Product Page
|
+-- Redux store
|
+-- products
+-- cart
+-- user
The URL may contain:
/products/101
Redux may contain:
cart
user
products
They solve different problems.
Router
Manages:
Navigation + URL
Redux
Manages:
Global application state
Do not use Redux simply because you need routing.
44. React Router with Forms
Modern React Router also supports route-oriented data APIs.
Depending on the router architecture you choose, routes can define:
- loaders
- actions
- forms
- error boundaries
This can move data loading and mutations closer to the route definition.
For example, a route can conceptually be:
{
path: "/products",
loader: loadProducts,
element: <Products />
}
Then the route can load its data before rendering the page.
45. Loader Concept
A loader is used to load route data.
Conceptually:
User navigates to /products
|
v
Router executes loader
|
v
API request
|
v
Product data
|
v
Products component
This is different from manually doing everything inside:
useEffect()
It allows routing and data loading to be integrated.
46. Example of createBrowserRouter
React Router provides a data-router approach using:
createBrowserRouter()
Example:
import {
createBrowserRouter,
RouterProvider
} from "react-router-dom";
const router = createBrowserRouter([
{
path: "/",
element: <Home />
},
{
path: "/products",
element: <Products />
}
]);
function App() {
return (
<RouterProvider router={router} />
);
}
This is another important way to configure React Router.
47. JSX Routes vs Data Router Configuration
There are two common styles.
JSX route configuration
<BrowserRouter>
<Routes>
<Route
path="/"
element={<Home />}
/>
<Route
path="/products"
element={<Products />}
/>
</Routes>
</BrowserRouter>
Data router
const router = createBrowserRouter([
{
path: "/",
element: <Home />
},
{
path: "/products",
element: <Products />
}
]);
Then:
<RouterProvider router={router} />
Both are valid approaches.
The data-router architecture becomes especially useful when you need route-level:
- loaders
- actions
- error handling
- data APIs
- navigation state
48. Lazy Loading Routes
Large applications should not necessarily download every page's JavaScript immediately.
You can lazy-load routes.
React provides:
lazy()
and:
Suspense
Example:
const Dashboard = lazy(
() => import("./Dashboard")
);
Then:
<Suspense fallback={<p>Loading...</p>}>
<Dashboard />
</Suspense>
The idea is:
Application starts
|
v
Load required code
|
v
User opens Dashboard
|
v
Download Dashboard chunk
|
v
Render Dashboard
This can improve initial load performance in large applications.
49. Route-Based Code Splitting
Imagine your application contains:
Home
Products
Reports
Admin
Analytics
Settings
Without code splitting, the browser may download a large JavaScript bundle.
With route-based lazy loading:
Initial load
|
+-- Home code
+-- Common code
Later:
|
+-- Products chunk
+-- Reports chunk
+-- Admin chunk
This is especially useful for large enterprise applications.
50. Error Handling
Modern React Router supports route-level error handling.
Conceptually:
{
path: "/products",
element: <Products />,
errorElement: <ErrorPage />
}
If something goes wrong in route handling/data loading, an appropriate error UI can be displayed.
This is better than allowing the whole application to become confusing when a route-specific operation fails.
51. Pending Navigation
Modern data-router APIs also expose navigation state.
Conceptually:
const navigation = useNavigation();
You can determine whether navigation is occurring.
For example:
if (navigation.state === "loading") {
return <p>Loading...</p>;
}
This can be used for:
- Loading indicators
- Progress indicators
- Disabling controls
- Navigation feedback
52. React Router in a Real E-Commerce Application
Imagine an e-commerce application:
/
├── products
│ ├── :productId
│ └── :productId/reviews
├── cart
├── checkout
├── login
└── account
├── profile
└── orders
└── :orderId
A possible route structure:
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
<Route
path="/products/:productId"
element={<ProductDetails />}
/>
<Route
path="/products/:productId/reviews"
element={<Reviews />}
/>
<Route path="/cart" element={<Cart />} />
<Route path="/login" element={<Login />} />
<Route element={<ProtectedRoute />}>
<Route
path="/account"
element={<AccountLayout />}
>
<Route
path="profile"
element={<Profile />}
/>
<Route
path="orders"
element={<Orders />}
/>
<Route
path="orders/:orderId"
element={<OrderDetails />}
/>
</Route>
</Route>
</Routes>
This demonstrates several important concepts together:
- Static routes
- Dynamic routes
- Nested routes
- Layouts
- Protected routes
- Route parameters
53. Real-World Admin Dashboard
An admin application might look like:
/admin
|
+-- Dashboard
|
+-- Users
| |
| +-- User Details
|
+-- Products
|
+-- Orders
|
+-- Reports
|
+-- Settings
A route configuration could be:
<Route
path="/admin"
element={<AdminLayout />}
>
<Route
index
element={<Dashboard />}
/>
<Route
path="users"
element={<Users />}
/>
<Route
path="users/:id"
element={<UserDetails />}
/>
<Route
path="products"
element={<Products />}
/>
<Route
path="orders"
element={<Orders />}
/>
<Route
path="reports"
element={<Reports />}
/>
<Route
path="settings"
element={<Settings />}
/>
</Route>
This is a very common enterprise pattern.
54. Routing Architecture for a Large Application
A larger project might use:
src/
│
├── components/
│ ├── Header.tsx
│ └── Sidebar.tsx
│
├── layouts/
│ ├── PublicLayout.tsx
│ └── AdminLayout.tsx
│
├── pages/
│ ├── Home.tsx
│ ├── Login.tsx
│ ├── Products.tsx
│ └── ProductDetails.tsx
│
├── routes/
│ └── AppRoutes.tsx
│
├── services/
│ └── productService.ts
│
├── context/
│ └── AuthContext.tsx
│
└── App.tsx
Then routing can be centralized.
For example:
function AppRoutes() {
return (
<Routes>
...
</Routes>
);
}
And:
function App() {
return (
<BrowserRouter>
<AppRoutes />
</BrowserRouter>
);
}
This becomes easier to maintain than putting every route directly into a huge App.tsx.
55. TypeScript with useParams
This is an important point.
useParams() values are strings.
Example:
const { id } = useParams();
The value should be treated as potentially undefined.
You can provide a type:
const { id } = useParams<{
id: string;
}>();
Then:
if (!id) {
return <p>Invalid product</p>;
}
Remember that URL values are strings.
Even if your URL contains:
/products/100
you receive:
id === "100"
not:
id === 100
If an API expects a number:
const productId = Number(id);
56. TypeScript with Navigation State
Suppose you navigate with state:
navigate("/product", {
state: {
productId: 101,
name: "Laptop"
}
});
You can read:
const location = useLocation();
But TypeScript may require you to define the expected state shape yourself.
A safer pattern is to define:
type ProductNavigationState = {
productId: number;
name: string;
};
Then use that type when reading the state.
The important idea is:
Navigation state is runtime data, so TypeScript does not magically validate that the other page actually received the expected object.
57. TypeScript Route Configuration
You can create route definitions using TypeScript:
const routes = [
{
path: "/",
element: <Home />
},
{
path: "/products",
element: <Products />
},
{
path: "/products/:id",
element: <ProductDetails />
}
];
The React Router types provide strong typing around routing APIs.
For most applications, you don't need to create complicated custom route types.
58. Authentication Flow with React Router
A common application flow is:
Application starts
|
v
Check authentication
|
+---- Not logged in
| |
| v
| Login Page
|
+---- Logged in
|
v
Dashboard
After login:
Login
|
v
API authentication
|
v
JWT/token received
|
v
Authentication state updated
|
v
navigate("/dashboard")
When accessing a protected page:
/dashboard
|
v
ProtectedRoute
|
v
Is user authenticated?
|
Yes ----> Dashboard
|
No
|
v
Login
59. React Router and JWT
React Router itself does not authenticate users.
Your backend may issue a JWT:
Login API
|
v
JWT
|
v
AuthContext
|
v
ProtectedRoute
|
v
React Router
React Router decides which UI route should be shown.
The API must still validate the JWT on protected API calls.
Therefore:
Frontend route protection improves user experience and navigation control, but backend authorization provides the actual security boundary.
60. React Router and API Calls
React Router doesn't replace Axios or fetch.
They have different responsibilities.
| Technology | Responsibility |
|---|---|
| React Router | Navigation and URL |
| Axios/fetch | HTTP requests |
| useState | Local component state |
| Context | Shared application state |
| Redux | Global state management |
| React Router loaders | Route-level data loading |
For example:
/products/101
|
v
React Router
|
v
ProductDetails
|
v
useParams()
|
v
id = 101
|
v
Axios
|
v
GET /api/products/101
61. When Should You Use React Router?
React Router is appropriate when your application has multiple navigable views.
Examples:
- E-commerce
- Admin dashboard
- Portfolio
- Learning platform
- SaaS application
- CRM
- ERP
- Blog
- Banking UI
- Social application
If your application has:
Home
Products
Product Details
Login
Dashboard
Profile
Settings
React Router is usually appropriate.
62. When You May Not Need React Router
You don't necessarily need React Router for a very small application.
For example:
Single component
Single screen
No URL-based navigation
No multiple pages
You could simply use:
function App() {
return <Counter />;
}
Adding a routing library to a tiny one-screen application may provide little value.
63. React Router vs Conditional Rendering
You could write:
const [page, setPage] = useState("home");
if (page === "home") {
return <Home />;
}
if (page === "about") {
return <About />;
}
This can work for simple UI switching.
But it doesn't naturally provide:
URL
Browser history
Deep linking
Back/forward navigation
Dynamic routes
Nested routes
Shareable URLs
React Router is designed for these requirements.
64. Common Mistake: Using <a> for Internal Navigation
Instead of:
<a href="/products">
Products
</a>
prefer:
<Link to="/products">
Products
</Link>
for internal SPA routes.
Use regular <a> when navigating to an external website, for example:
<a
href="https://example.com"
target="_blank"
rel="noreferrer"
>
External Website
</a>
65. Common Mistake: Forgetting BrowserRouter
If you use:
<Link to="/products">
Products
</Link>
but your application isn't inside a router, you can get routing-context errors.
Make sure the application is wrapped appropriately:
<BrowserRouter>
<App />
</BrowserRouter>
66. Common Mistake: Incorrect Nested Paths
Suppose:
<Route path="/admin" element={<AdminLayout />}>
<Route path="/users" element={<Users />} />
</Route>
The child route beginning with / is an absolute path.
For normal nested routing, use:
<Route path="users" element={<Users />} />
Then the final URL becomes:
/admin/users
This distinction is important.
67. Common Mistake: Forgetting Outlet
You define:
<Route path="/admin" element={<AdminLayout />}>
<Route path="users" element={<Users />} />
</Route>
but your layout does not contain:
<Outlet />
Then the child component has nowhere to render.
You generally need:
function AdminLayout() {
return (
<>
<Sidebar />
<Outlet />
</>
);
}
68. Common Mistake: Treating URL Parameters as Numbers
This:
/products/100
produces:
id === "100"
not:
id === 100
Therefore:
const numericId = Number(id);
may be required before sending it to an API that expects a numeric identifier.
69. Common Mistake: Relying on Route Protection for Security
This is dangerous:
if (user.role !== "admin") {
return <Navigate to="/login" />;
}
This only controls the frontend.
A user can still call your API directly.
Your backend should also check:
JWT
+
Claims
+
Roles/Permissions
For example:
React Router
|
| UI protection
v
Admin Page
|
v
API
|
| Backend authorization
v
Database
Both frontend and backend should enforce appropriate controls.
70. Common Mistake: Putting Everything in App.tsx
This:
function App() {
// 100 routes
// authentication
// layouts
// navigation
// business logic
}
becomes difficult to maintain.
For larger applications, separate:
routes/
layouts/
pages/
components/
services/
according to your application's size and architecture.
71. Best Practice: Keep URLs Meaningful
Prefer:
/products
/products/101
/orders/500
/users/25
instead of:
/page1
/page2
/x123
Good URLs make applications easier to understand and debug.
72. Best Practice: Use Query Parameters for UI Filters
Instead of keeping all search/filter state only in React state:
const [category, setCategory] =
useState("laptop");
consider URL state when it should be shareable:
/products?category=laptop
This is especially useful for:
- Search
- Filters
- Pagination
- Sorting
- Tabs
73. Best Practice: Use Layout Routes
If multiple pages share:
Header
Sidebar
Footer
use a layout route.
Instead of duplicating:
<Header />
<Sidebar />
<Footer />
in every page, use:
<Layout>
<Outlet />
</Layout>
This improves maintainability.
74. Best Practice: Use Lazy Loading for Large Applications
For large applications:
const Reports = lazy(
() => import("./Reports")
);
can reduce initial JavaScript loading.
Use route-based code splitting especially when some pages are large or rarely visited.
75. Best Practice: Don't Put Everything in the URL
The URL is useful for navigation and shareable state.
But don't put sensitive information into:
?token=...
or:
/users?password=...
URLs can appear in browser history, logs, analytics, server infrastructure, and referrer-related contexts.
Keep sensitive information out of URLs.
76. Best Practice: Keep Route Names Consistent
For example:
/products
/products/:id
/products/:id/reviews
is clearer than mixing unrelated naming styles.
For an application with many resources, establish conventions early.
77. Important React Router Hooks
These are some of the most important hooks to remember:
| Hook | Purpose |
|---|---|
useNavigate() |
Programmatic navigation |
useParams() |
Read route parameters |
useSearchParams() |
Read/update query parameters |
useLocation() |
Read current URL/location |
useMatch() |
Check whether a route pattern matches |
useOutlet() |
Access rendered child route |
useOutletContext() |
Share context from parent route |
For beginner and intermediate development, the first four are the most commonly used.
78. Important React Router Components
| Component | Purpose |
|---|---|
BrowserRouter |
Provides browser routing context |
Routes |
Contains route definitions |
Route |
Defines a route |
Link |
Navigation |
NavLink |
Navigation with active-route information |
Navigate |
Redirect/navigation during rendering |
Outlet |
Renders child route |
RouterProvider |
Runs a data router |
Form |
Router-aware form navigation in data-router usage |
79. Complete Practical Example
Let's build a small application with:
Home
Products
Product Details
About
Admin Dashboard
404
We'll also use:
- Navigation
- Dynamic route
- Nested route
- Layout
useParamsuseNavigateOutlet- 404 handling
Project structure
src/
│
├── main.tsx
│
├── App.tsx
│
├── layouts/
│ └── AdminLayout.tsx
│
├── pages/
│ ├── Home.tsx
│ ├── Products.tsx
│ ├── ProductDetails.tsx
│ ├── About.tsx
│ ├── Dashboard.tsx
│ └── NotFound.tsx
│
└── components/
└── Navbar.tsx
main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
ReactDOM.createRoot(
document.getElementById("root")!
).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
App.tsx
import {
Routes,
Route
} from "react-router-dom";
import Navbar from "./components/Navbar";
import Home from "./pages/Home";
import Products from "./pages/Products";
import ProductDetails from "./pages/ProductDetails";
import About from "./pages/About";
import Dashboard from "./pages/Dashboard";
import AdminLayout from "./layouts/AdminLayout";
import NotFound from "./pages/NotFound";
function App() {
return (
<>
<Navbar />
<Routes>
<Route
path="/"
element={<Home />}
/>
<Route
path="/products"
element={<Products />}
/>
<Route
path="/products/:id"
element={<ProductDetails />}
/>
<Route
path="/about"
element={<About />}
/>
<Route
path="/admin"
element={<AdminLayout />}
>
<Route
index
element={<Dashboard />}
/>
</Route>
<Route
path="*"
element={<NotFound />}
/>
</Routes>
</>
);
}
export default App;
Navbar.tsx
import {
NavLink
} from "react-router-dom";
export default function Navbar() {
return (
<nav>
<NavLink to="/">
Home
</NavLink>
{" | "}
<NavLink to="/products">
Products
</NavLink>
{" | "}
<NavLink to="/about">
About
</NavLink>
{" | "}
<NavLink to="/admin">
Admin
</NavLink>
</nav>
);
}
Products.tsx
import { Link } from "react-router-dom";
const products = [
{
id: 101,
name: "Laptop"
},
{
id: 102,
name: "Keyboard"
},
{
id: 103,
name: "Mouse"
}
];
export default function Products() {
return (
<div>
<h1>Products</h1>
{products.map(product => (
<div key={product.id}>
<Link to={`/products/${product.id}`}>
{product.name}
</Link>
</div>
))}
</div>
);
}
ProductDetails.tsx
import {
useNavigate,
useParams
} from "react-router-dom";
export default function ProductDetails() {
const { id } = useParams();
const navigate = useNavigate();
return (
<div>
<h1>Product Details</h1>
<p>
Product ID: {id}
</p>
<button
onClick={() => navigate("/products")}
>
Back to Products
</button>
</div>
);
}
AdminLayout.tsx
import {
Link,
Outlet
} from "react-router-dom";
export default function AdminLayout() {
return (
<div>
<h1>Admin Panel</h1>
<nav>
<Link to="/admin">
Dashboard
</Link>
</nav>
<hr />
<Outlet />
</div>
);
}
Dashboard.tsx
export default function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
<p>
Welcome to Admin Dashboard.
</p>
</div>
);
}
NotFound.tsx
export default function NotFound() {
return (
<div>
<h1>404</h1>
<p>
Page Not Found
</p>
</div>
);
}
80. Complete Application Flow
Now suppose the user starts at:
/
React Router matches:
<Route
path="/"
element={<Home />}
/>
So:
Home
is displayed.
The user clicks:
Products
React Router navigates to:
/products
The router matches:
<Route
path="/products"
element={<Products />}
/>
Now Products renders.
The user clicks:
Laptop
The application navigates to:
/products/101
The router matches:
<Route
path="/products/:id"
element={<ProductDetails />}
/>
Then:
useParams()
returns:
id = "101"
The page displays:
Product Details
Product ID: 101
This is the complete routing flow:
User clicks Product
|
v
<Link>
|
v
URL changes
/products/101
|
v
React Router matches
/products/:id
|
v
ProductDetails
|
v
useParams()
|
v
id = "101"
81. Real-World Architecture
For a real application such as an online learning platform, you could have:
/
├── courses
├── courses/:courseId
├── courses/:courseId/lessons
├── login
├── register
├── cart
├── checkout
│
└── account
├── profile
├── courses
└── orders
And an admin area:
/admin
├── dashboard
├── courses
├── courses/:courseId
├── students
├── orders
└── settings
This is where React Router becomes much more valuable than manually managing page state.
82. React Router Mental Model
The easiest way to understand React Router is to remember four questions.
1. Where am I?
Use:
useLocation()
2. What resource am I viewing?
Use:
useParams()
Example:
/products/101
means:
resource = product
id = 101
3. Where should I go?
Use:
<Link />
or:
navigate()
4. What should render here?
React Router determines this from:
<Route />
So:
URL
↓
Route Matching
↓
Component
↓
Component Data
↓
API / State
↓
UI
83. React Router vs React State
A very important distinction:
React state
Use state for:
Modal open/closed
Selected tab
Form values
Loading state
Temporary UI state
Router state / URL
Use routing for:
Current page
Current resource
Search/filter state that should be shareable
Pagination that should be bookmarkable
For example:
Modal:
useState()
Product ID:
URL parameter
Search:
URL query parameter
User authentication:
Context/store + backend authentication
Page navigation:
React Router
Choosing the correct place for state makes an application much easier to maintain.
84. Interview Questions and Answers
1. What is React Router?
React Router is a routing library for React applications. It maps URLs to React components and allows navigation without a full browser page reload.
2. Why is React Router used?
It provides client-side routing for SPAs, including navigation, dynamic routes, nested routes, parameters, redirects, protected routes, and layouts.
3. What is BrowserRouter?
BrowserRouter provides browser-based routing context using the browser History API.
4. What is the difference between Routes and Route?
Routes contains the route definitions, while each Route defines a URL pattern and the component to render.
5. What is Link?
Link provides client-side navigation between routes without performing a normal full-page browser navigation.
6. What is NavLink?
NavLink works like Link but also provides information about whether the current route is active.
7. What is useNavigate?
useNavigate is a hook used for programmatic navigation.
const navigate = useNavigate();
navigate("/dashboard");
8. What is useParams?
useParams reads dynamic values from the URL.
<Route path="/products/:id" element={<Product />} />
const { id } = useParams();
9. What is Outlet?
Outlet is the placeholder where a matched child route is rendered.
10. What is nested routing?
Nested routing allows child routes to render inside a parent route/layout.
Example:
/admin
/admin/users
/admin/products
11. What is a protected route?
A protected route prevents unauthorized users from accessing certain UI routes and commonly redirects them to login or an unauthorized page.
12. Is React Router enough for security?
No. React Router provides frontend navigation control. Backend APIs must independently enforce authentication and authorization.
13. What is the difference between Navigate and useNavigate?
useNavigate() is used programmatically inside component logic. <Navigate /> performs navigation through rendering.
14. What is a dynamic route?
A route containing a parameter such as:
/products/:id
which can match:
/products/101
/products/102
15. What is the difference between route parameters and query parameters?
Route parameters identify resources:
/products/101
Query parameters usually represent filtering, searching, sorting, or pagination:
/products?category=laptop&page=2
16. What is an index route?
An index route is the default child route of a parent route.
<Route index element={<Dashboard />} />
17. Why use Outlet?
It allows a parent layout to render the currently matched child route without duplicating layout code.
18. How do you create a 404 page?
Use a wildcard route:
<Route path="*" element={<NotFound />} />
19. How do you navigate after login?
Usually:
navigate("/dashboard", {
replace: true
});
20. How does React Router work with API calls?
The route can provide identifiers such as:
/products/101
The component reads the ID with useParams() and uses it to request:
GET /api/products/101
21. Can React Router replace Redux?
No. They solve different problems. React Router handles navigation and URL state, while Redux manages application state.
22. What is lazy loading in routing?
It means loading a page's JavaScript only when that route is needed, reducing the initial bundle size.
23. What is useLocation()?
It provides information about the current URL/location, such as pathname, search parameters, and hash.
24. Can React Router protect API endpoints?
No. API protection must be implemented on the server.
25. Why use query parameters?
They are useful for URL-shareable state such as:
search
filter
sort
page
For example:
/products?search=laptop&page=2
85. Important Points to Remember
BrowserRouter
|
v
Routes
|
+---- Route
| |
| +---- Component
|
+---- Nested Route
|
+---- Outlet
Remember these core concepts:
| Concept | Main Purpose |
|---|---|
BrowserRouter |
Enable browser routing |
Routes |
Manage routes |
Route |
Map URL to component |
Link |
Navigate |
NavLink |
Navigate + active state |
useNavigate |
Programmatic navigation |
useParams |
Read URL parameters |
useSearchParams |
Read/update query parameters |
useLocation |
Read current location |
Outlet |
Render child routes |
Navigate |
Redirect |
index route |
Default child route |
* route |
Catch unmatched URLs |
lazy + Suspense |
Lazy-load route components |
loader |
Route-level data loading |
action |
Route-level data mutation |
86. The Most Important Mental Model
If you remember only one thing about React Router, remember this:
URL
|
v
React Router
|
v
Route Matching
|
v
React Component
|
+--------+--------+
| |
v v
Route Data Application State
| |
+--------+--------+
|
v
UI
For example:
/products/101?tab=reviews
can be understood as:
/products
|
+-- :id = 101
|
+-- tab = reviews
Then:
useParams()
can provide:
id = "101"
and:
useSearchParams()
can provide:
tab = "reviews"
Your component can then use those values to determine what data and UI to display.
87. Summary
React Router is the routing system that allows a React application to support multiple URL-based views while remaining a Single Page Application.
The most important concepts are:
BrowserRouter
↓
Routes
↓
Route
↓
Component
For navigation:
<Link />
<NavLink />
useNavigate()
For reading URL information:
useParams()
useSearchParams()
useLocation()
For nested applications:
Outlet
Nested Routes
Layout Routes
Index Routes
For real-world applications:
Authentication
Protected Routes
Role-based Routes
Dynamic Routes
Query Parameters
Lazy Loading
Error Handling
Route-level Data Loading
The key design principle is:
Use React Router to represent navigation and URL state; use React state, Context, Redux, or other state-management tools for application state; and always enforce security on the backend as well.
Once you understand routes → navigation → parameters → nested routes → layouts → protected routes, you have the foundation needed to build routing for most real-world React applications.