When building a modern web application with React, one of the most essential features you'll need to implement is navigation—the ability to switch between different views or pages. This is where React Routing comes in. React is a powerful library for building dynamic user interfaces, but it doesn't come with built-in routing. Instead, you use a library like React Router to manage navigation in your app.
In this article, we’ll dive deep into React Routing, explain how it works, and walk through a series of examples that will help you understand how to set up routes and navigate through your app effectively.
At the core of any web application is the concept of routing—the mechanism that handles which content is shown based on the URL. When a user navigates to a specific URL in the browser, routing determines which view (or component) should be displayed.
In traditional websites, when you click on a link, the entire page reloads. In a React application, however, we often want to change the content on the page without doing a full reload. This makes the app feel faster and more like a native application.
React Router helps accomplish this by allowing you to manage routing in a Single Page Application (SPA). SPAs load a single HTML page and dynamically update the content as the user interacts with the app.
React Router provides several essential features for navigation in a React app:
In React Router, routing is managed by different components that work together to handle URL matching and rendering the appropriate components. Let’s break down these components and how they work.
<Router>
component keeps track of the URL and determines which components should be displayed.<Route>
defines a path and the component that should be rendered when the URL matches that path.<Link>
component is used to create clickable links that update the URL without reloading the page.<Switch>
component ensures that only the first matching route is rendered, which helps prevent multiple routes from being displayed at once.To get started with React Router, you first need to install the library. Open your terminal and run the following command:
npm install react-router-dom
This command will install react-router-dom, the package that enables routing in React web applications. The “dom” part refers to routing for web applications (as opposed to native mobile apps).
Let’s walk through a simple example where we set up basic routing for three pages: Home, About, and Contact.
Create Your Components: First, we need to create three simple components for each page.
// Home.js
function Home() {
return <h2>Welcome to the Home Page!</h2>;
}
export default Home;
// About.js
function About() {
return <h2>Learn more About Us!</h2>;
}
export default About;
// Contact.js
function Contact() {
return <h2>Contact Us!</h2>;
}
export default Contact;
2. Set Up Routing in the App:
Now that we have our components, we can set up React Router in the main App.js
file.
import React from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
import Home from './Home';
import About from './About';
import Contact from './Contact';
function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/contact">Contact</Link>
</li>
</ul>
</nav>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
</div>
</Router>
);
}
export default App;
<Router>
: This component keeps track of the browser’s history and determines which component to render based on the URL.<Link>
: This component is like an anchor (<a>
) tag, but it doesn’t cause the page to reload. When clicked, it updates the URL and displays the corresponding component.<Switch>
: This is used to ensure only the first matching <Route>
is rendered. Without <Switch>
, multiple routes could be rendered if their paths overlap.exact
: The exact
keyword is used with the Home route so that it only renders the Home
component when the URL is exactly /
.Now, when you run the app, you’ll have three pages—Home, About, and Contact—that you can navigate between using the links.
In more complex apps, you may want to display different components inside one another, which is known as nested routing. Let's say we want to add a "Team" page inside the "About" page.
Create the Team Component:
// Team.js
function Team() {
return <h3>Our Team</h3>;
}
export default Team;
2. Update the About Component to include nested routing:
import React from 'react';
import { Route, Link } from 'react-router-dom';
import Team from './Team';
function About() {
return (
<div>
<h2>About Us</h2>
<nav>
<Link to="/about/team">Our Team</Link>
</nav>
<Route path="/about/team" component={Team} />
</div>
);
}
export default About;
In this example, we added a link to the "Team" page inside the "About" page and set up a nested route that will render the Team
component when the user navigates to /about/team
.
React Router allows you to navigate to different routes programmatically, meaning you can use JavaScript to change the route without needing a link.
For example, you might want to navigate to a different page after a form submission. Here’s how you can do that using the useHistory
hook.
import React from 'react';
import { useHistory } from 'react-router-dom';
function Contact() {
const history = useHistory();
const handleSubmit = () => {
// Navigate to the "Thank You" page after form submission
history.push('/thank-you');
};
return (
<div>
<h2>Contact Us</h2>
<button onClick={handleSubmit}>Submit</button>
</div>
);
}
export default Contact;
The Routes component is a container for all your route definitions, while Route defines a mapping between a URL path and a component:
import { Routes, Route } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
);
}
The Link component is used to create navigation links in your application. It's similar to an <a> tag but prevents page reloads:
import { Link } from 'react-router-dom';
function Navigation() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/contact">Contact</Link>
</nav>
);
}
NavLink is a special version of Link that can be styled differently when it matches the current URL:
import { NavLink } from 'react-router-dom';
function Navigation() {
return (
<nav>
<NavLink
to="/"
className={({ isActive }) => isActive ? 'active' : ''}
>
Home
</NavLink>
</nav>
);
}
You can capture dynamic values from the URL using parameters:
// Route definition
<Route path="/user/:id" element={<UserProfile />} />
// In UserProfile component
import { useParams } from 'react-router-dom';
function UserProfile() {
const { id } = useParams();
return <h1>User Profile {id}</h1>;
}
React Router supports nested routing, allowing you to create more complex layouts:
function App() {
return (
<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
);
}
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Outlet /> {/* Child routes render here */}
</div>
);
}
You can navigate programmatically using the useNavigate hook:
import { useNavigate } from 'react-router-dom';
function LoginButton() {
const navigate = useNavigate();
const handleLogin = () => {
// Perform login logic
navigate('/dashboard');
};
return <button onClick={handleLogin}>Log In</button>;
}
A common requirement is to protect certain routes based on authentication status:
function ProtectedRoute({ children }) {
const isAuthenticated = checkAuthStatus(); // Your auth logic here
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return children;
}
// Usage
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
Create consistent layouts across multiple routes:
function Layout() {
return (
<div>
<Header />
<Outlet />
<Footer />
</div>
);
}
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Route>
</Routes>
Define default child routes using index routes:
<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route index element={<Overview />} />
<Route path="profile" element={<Profile />} />
</Route>
</Routes>
React Router is an essential tool for building dynamic, single-page React applications. It allows you to set up routes, navigate between pages, and render the correct components based on the URL all without reloading the page.