What is ROUTING?
Routing refers to the process of navigating between different pages or views in a single-page application (SPA) without reloading the entire page.
- It keeps the UI in sync with the current browser URL.
- Allows us to build Single Page Applications (SPA).
Why Routing in React?
React apps are SPAs, meaning there's only one HTML file (index.html
), but multiple views (pages) that users can navigate to. Routing helps manage these views by matching the URL to the correct component.
It enables client-side navigation without full-page reloads, allowing users to move smoothly between URLs like /home
, /about
, or /contact
, each displaying different components.
React doesn’t have built-in routing, so we use a library like React Router (react-router-dom) for handling routing.
What is a Single Page Application (SPA)?
A Single Page Application (SPA) dynamically updates the page without reloading it, providing a seamless user experience.
- Runs entirely in the browser (Client Side).
- Different URLs load different React components.
- Uses JavaScript (React) to update the UI dynamically.
- Fetches additional data via APIs (e.g., from a backend server).
When the user clicks a link, the URL updates, and React dynamically loads the corresponding component.
React Router
React Router is the most popular library to handle navigation inside a React app.
- Enables URL-based navigation.
- Changes browser URLs without refreshing the page.
- Keeps the UI in sync with the URL.
🔧 Installation
npm install react-router-dom
Defining Routes
With routing, we match different URLs to different UI views. In the case of React, we match a URL to a specific React Component, and we call each of these matches
routes
.
Since React Router v6.4, there are two main ways to define routes. We'll focus on the traditional declarative way.
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
import Home from "./Home";
import About from "./About";
function App() {
return (
<BrowserRouter> {/* 🚀 Enables routing */}
<Routes> {/* 🚦 Manages route paths */}
<Route index element={<Home />} /> {/* Default route */}
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
function Nav() {
return (
<nav>
<Link to="/">Home</Link> {/* Link to Home */}
<Link to="/about">About</Link> {/* Link to About */}
</nav>
);
}
Key Concepts 🔑
-
<BrowserRouter>
– The Router Provider- It's the top-level component that enables routing in your React application.
- It leverages the HTML5 History API to keep your UI synchronized with the browser URL.
- Crucially, without
<BrowserRouter>
, React Router won't be able to manage your application's routes.
-
<Routes>
– Routing Container- This component acts as a container for your individual
<Route>
definitions. - It intelligently iterates through its
<Route>
children and renders the first one whosepath
matches the current browser URL. - Think of
<Routes>
as a central highway dispatcher, directing traffic to the appropriate exits. - It's the successor to the older
<Switch>
component in previous versions of React Router.
- This component acts as a container for your individual
-
<Route>
– Define a Path and Component- Each
<Route>
component serves as a mapping between a specific URL path and a corresponding React component. - When the browser URL matches the
path
of a<Route>
, that route'selement
(the React component) is rendered. -
index
prop defines the default child route (instead ofpath="/"
). - Page Not Found Handling:
<Route index element={<Home />} /> <Route path="*" element={<PageNotFound />} />
The
path="*"
acts as a catch-all. If no other defined route matches the current URL, this route will be matched, and the<PageNotFound>
component will be displayed. - Each
-
<NavLink>
/<Link>
– Navigation Without Reload- These components are your primary tools for navigating between different routes within your SPA without triggering a full page reload from the server.
- They render as standard
<a>
tags in the HTML but intercept the click event to perform client-side navigation managed by React Router. -
<NavLink>
vs.<Link>
:-
<NavLink>
is a specialized version of<Link>
that provides built-in styling capabilities for the currently active route. - It automatically applies an
active
class (by default) to the rendered link when itsto
prop matches the current URL. - You can customize this behavior using the
className
orstyle
props, or by using theisActive
prop for more fine-grained control.
-
import { NavLink } from "react-router-dom"; function Navigation() { return ( <nav> <NavLink to="/">Home</NavLink> <NavLink to="/about">About</NavLink> </nav> ); }
-
Nested Routes
- As your application grows, you might encounter scenarios where certain sections have their own sub-navigation and views. This is where nested routes come in handy.
- Imagine a
/dashboard
section with sub-pages like/dashboard/profile
and/dashboard/settings
. - To implement this, you define child
<Route>
components within a parent<Route>
. -
The key to rendering the content of these nested routes is the
<Outlet />
component in the parent route's component.
<Routes> <Route path="/dashboard" element={<Dashboard />}> <Route path="profile" element={<Profile />} /> <Route path="settings" element={<Settings />} /> </Route> </Routes>
-
<Outlet>
in React Router- The
<Outlet>
component serves as a placeholder in the component rendered by a parent route. - When a child route of that parent route matches the current URL, its corresponding component is rendered inside the
<Outlet>
within the parent. -
Why is
<Outlet>
essential?- It enables you to create reusable layouts. Common UI elements like navigation bars, sidebars, and footers can be defined in the parent component, while the specific content for the child routes is dynamically injected into the
<Outlet>
. - This promotes a clean and organized component structure.
- It enables you to create reusable layouts. Common UI elements like navigation bars, sidebars, and footers can be defined in the parent component, while the specific content for the child routes is dynamically injected into the
import { Outlet, Link } from "react-router-dom"; const Dashboard = () => { return ( <div> <nav> <Link to="/profile">Profile</Link> <Link to="/settings">Settings</Link> </nav> <hr /> <Outlet /> {/* Child route components will be rendered here */} </div> ); }; export default Dashboard;
- The
Dynamic Routes with URL Parameters
Dynamic routes allow you to create routes that can handle variable parts of the URL. This is useful for displaying details of a specific item, like a product or a user profile.
import { useParams } from 'react-router-dom';
function ProductDetails() {
const { productId } = useParams();
return <div>Product ID: {productId}</div>;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/products/:productId" element={<ProductDetails />} />
</Routes>
</BrowserRouter>
);
}
-
useParams()
hook: This React Router hook allows you to access the dynamic parameters from the current URL. You can call this hook within the functional component rendered by the dynamic route (in this case, ProductDetails). It returns an object where the keys are the parameter names defined in the path (e.g., productId) and the values are the corresponding segments from the URL. -
/:productId
: This syntax within the path prop of the<Route>
defines a dynamic segment. Any value in this position of the URL will be captured as the productId parameter. For example, if the URL is/products/42
, theuseParams()
hook in ProductDetails will return { productId: "42" }.
Programmatic Navigation
useNavigate
Hook
The useNavigate
hook allows you to programmatically navigate to different routes. This is often used after actions like form submissions or for handling authentication redirects.
import { useNavigate } from 'react-router-dom';
function Home() {
const navigate = useNavigate();
const handleClick = () => {
navigate('/about');
};
return <button onClick={handleClick}>Go to About</button>;
}
<Navigate />
Component
The <Navigate />
component is used to redirect the user to a different route, often based on certain conditions like user authentication
import { Navigate } from 'react-router-dom';
function ProtectedRoute({ isLoggedIn, children }) {
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return children;
}
-
replace
prop: Replaces the current entry in the history stack. - This is useful for auth checks and redirection.
How Routing Changes Component Structure in React
- Without Router (Traditional Component Structure) Normally, in a simple React app (without a router), we structure components inside the App component like this:
function App() {
return (
<div>
<Header />
<Main />
<Footer />
</div>
);
}
Here, App acts like a parent container that holds all components, and all of them are typically rendered together.
-
When React Router Comes Into Play
When we introduce React Router, the way we structure App changes. Instead of keeping all components directly inside App, we primarily keep the
<BrowserRouter>
,<Routes>
, and<Route>
configurations there. The actual page content is rendered by the components matched by the routes.
Why?
-
Routing Controls What to Show
- Before Router: App always renders everything.
- With Router: Different pages (routes) should load only when needed.
-
Why is this better? 📌
- Improved Performance: Only the required components for the current route are loaded and rendered, reducing the initial load time and improving overall performance.
- Smoother User Experience: Navigation between different views happens without full page reloads, providing a more seamless and faster user experience.
Understanding React Router with a Highway Analogy
React Router Concept | Real-World Analogy |
---|---|
BrowserRouter |
🛣️ The road network that enables travel. Without it, there are no roads. |
Routes |
🚗 The highway with multiple exits (routes). |
Route |
🛑 A specific exit that leads to a destination (component). |
Link |
🚦 Signboards that direct users to different routes. |
<Outlet /> |
🛣️ The location on the highway where nested exits merge. |
- Without
BrowserRouter
, there are no roads! - Without
Routes
, there are no exits! - Without
Route
, you can’t reach your destination! - Without
Outlet
, nested routes have nowhere to render.
✨ Final Thoughts
Routing is the backbone of navigation in modern React applications. It allows us to create multi-page experiences without full page reloads, making our apps feel faster, more dynamic, and more like native applications.
With React Router, we can:
- Map URLs to components easily.
- Enable smooth client-side navigation.
- Organize large applications into clean, scalable route structures.
- Enhance user experience with dynamic routing, nested layouts, protected routes, and programmatic navigation.
As you build more advanced React apps, mastering routing will unlock a whole new level of power and flexibility in your projects.
In short, React Router bridges the gap between a simple app and a fully functional web experience. 🚀
📚 What's Next?
This post focused on the traditional declarative routing using React Router 6.
However, to keep things clean and digestible, I’ll cover some advanced topics separately in the next post:
- Using Suspense with React Router (for lazy loading routes) ⚡
- New Features and Changes in React Router v7🆕
Stay tuned for a deep dive into modern routing patterns and performance optimization techniques coming soon!
Top comments (2)
insane how clean you can make the app structure with just a few lines. ever notice if super fancy routing setups actually help or just make things messy over time?