Hello! Let's continue our journey with React Router.
In the last lesson, we successfully set up the routing map for our application. We defined different routes and mapped them to specific page components. Now, if you run your app, you can manually type /, /about, or /products into the browser's address bar to see the different pages. The problem is, users can't navigate without knowing these URLs. We need to provide clickable links.
Today's lesson focuses on exactly that. We will learn how to use the <Link> and <NavLink> components from React Router to create a declarative and accessible navigation menu. This is how you empower users to move through your single-page application (SPA) without triggering disruptive full-page reloads.
Coming from a Laravel background, you're familiar with generating URLs in your Blade templates, perhaps using the route() helper function inside an <a> tag. React Router's <Link> component serves a similar purpose but with a crucial difference: it manages navigation on the client side, maintaining the speed and state of your SPA.
1. The Problem with Standard <a> Tags
Your first instinct might be to use a standard HTML anchor tag, like <a href="/about">About Us</a>. While this will take the user to the correct URL, it does so by sending a brand new request to the server and causing a full page refresh.
This behavior defeats the entire purpose of a Single-Page Application. When the page reloads:
- Your entire React application is re-initialized from scratch.
- Any state you were managing (like form inputs or user data) is lost.
- It's a slower, less fluid experience for the user.
To solve this, React Router provides its own navigation components.
2. The <Link> Component: Basic Navigation
The <Link> component is the fundamental building block for navigation in a React Router application. It renders an accessible <a> tag in the HTML, but it intercepts the click event. Instead of letting the browser handle it, Link programmatically updates the URL in the address bar and tells React Router to render the appropriate component, all without a page reload.
To understand its basic usage, please read the following section from the "React Routing Guide" article.
This section introduces the Link component and shows how to implement a basic navigation menu. Pay close attention to how it's imported and used with the to prop.
Read the section titled The Link Component. You can find it under the 'Building Navigation in React Routing' heading. Focus on the code example that shows a simple <ul> menu.
Based on that reading, let's create a dedicated Navbar component for our application.
- Create a new file:
src/components/Navbar.jsx. - Add the following code to it. This creates a simple navigation bar using
Link.
// src/components/Navbar.jsx
import React from 'react';
import { Link } from 'react-router-dom';
const Navbar = () => {
return (
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/products">Products</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
</nav>
);
};
export default Navbar;
- Now, open
src/App.jsxand import your newNavbarcomponent. Place it above the<Routes>so it appears on every page.
// src/App.jsx
import React from 'react';
import { Routes, Route } from 'react-router-dom';
// Import your page components
import HomePage from './pages/HomePage';
import AboutPage from './pages/AboutPage';
import ProductsPage from './pages/ProductsPage';
import NotFoundPage from './pages/NotFoundPage';
// Import your new Navbar component
import Navbar from './components/Navbar';
function App() {
return (
<div>
<Navbar /> {/* <-- Add the Navbar here */}
<main>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/products" element={<ProductsPage />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</main>
</div>
);
}
export default App;
If you run your app now, you'll see the navigation links. Clicking them will change the page content instantly without a browser refresh. This works, but it's missing a key piece of user feedback: which link is currently active?
3. The <NavLink> Component: Styling Active Links
For a good user experience, the currently active navigation link should be styled differently (e.g., bolded or colored). This provides crucial visual feedback. This is where <NavLink> comes in.
<NavLink> is a special version of <Link> that knows whether or not it is "active".
Navigating the Cosmos: Exploring NavLink in React - CodeSignal
This article explains the 'superpower' of NavLink: its ability to style itself when it's active. It clearly contrasts NavLink with Link and introduces the modern way of applying styles.
Read from the beginning down to the end of the Dynamic Styling with style attribute section. Focus on how NavLink differs from Link and how the isActive property is used within a function to apply conditional styles.
As the article explains, in React Router v6, you pass a function to the style or className prop. This function receives an object with an isActive boolean property, which you can use to return the correct style or class name.
Let's update our Navbar.jsx to use NavLink.
- Open
src/components/Navbar.jsxand changeLinktoNavLink. - We'll use the
styleprop to apply an inline style when the link is active.
// src/components/Navbar.jsx
import React from 'react';
import { NavLink } from 'react-router-dom'; // Import NavLink instead of Link
const Navbar = () => {
const navLinkStyles = ({ isActive }) => {
return {
fontWeight: isActive ? 'bold' : 'normal',
textDecoration: isActive ? 'underline' : 'none',
color: 'blue'
};
};
return (
<nav>
<ul>
<li>
<NavLink to="/" style={navLinkStyles}>Home</NavLink>
</li>
<li>
<NavLink to="/products" style={navLinkStyles}>Products</NavLink>
</li>
<li>
<NavLink to="/about" style={navLinkStyles}>About</NavLink>
</li>
</ul>
</nav>
);
};
export default Navbar;
In this example, we defined a function navLinkStyles that takes the { isActive } object and returns a style object. If isActive is true, the font weight becomes 'bold' and an underline appears. This is a clean way to manage conditional styling logic.
Styling with CSS Classes
While inline styles are great for simple cases, using CSS classes is often more maintainable. You can also pass a function to the className prop.
- First, add a CSS rule to your global stylesheet (e.g.,
src/index.cssorsrc/App.css).
/* Add this to your CSS file */
.active-link {
font-weight: bold;
text-decoration: underline;
}
- Then, update
Navbar.jsxto use theclassNameprop instead ofstyle.
// src/components/Navbar.jsx
import React from 'react';
import { NavLink } from 'react-router-dom';
const Navbar = () => {
return (
<nav>
<ul>
<li>
<NavLink to="/" className={({ isActive }) => (isActive ? 'active-link' : '')}>
Home
</NavLink>
</li>
<li>
<NavLink to="/products" className={({ isActive }) => (isActive ? 'active-link' : '')}>
Products
</NavLink>
</li>
<li>
<NavLink to="/about" className={({ isActive }) => (isActive ? 'active-link' : '')}>
About
</NavLink>
</li>
</ul>
</nav>
);
};
export default Navbar;
This approach keeps your styling concerns separate from your component logic, which is generally a good practice.
Conclusion
Congratulations! You've now built a fully functional and accessible navigation bar for your SPA. You have moved from just defining routes to allowing users to interact with them seamlessly.
Key Takeaways:
- Never use a standard
<a href="...">tag for internal navigation in a React SPA, as it causes a full page reload. - Use the
<Link to="...">component for basic, clickable navigation that preserves the SPA experience. - Use the
<NavLink to="...">component when you need to apply special styling to the currently active link, which is crucial for good user experience. - In React Router v6, you apply active styles to a
<NavLink>by passing a function to thestyleorclassNameprop. This function receives an{ isActive }property.
Preview of the Next Lesson:
Our current routes are static (/, /about, /products). But what about pages that need to display specific items, like a single product from a list? In the next lesson, we will explore dynamic routes, where we can use URL parameters (e.g., /products/:id) to render content dynamically.