React Router
Client-side routing and navigation
What Is React Router?
React Router is the standard library for routing in React applications. It enables client-side navigation, allowing users to move between pages without full page reloads—making your app feel fast and responsive like a native app.
Installation
npm install react-router-dom
Basic Setup
import { BrowserRouter, Routes, Route } from 'react-router-dom';
// Page components
function Home() {
return <h1>Home Page</h1>;
}
function About() {
return <h1>About Page</h1>;
}
function Contact() {
return <h1>Contact Page</h1>;
}
// App with routing
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
);
}
Navigation with Link
import { Link, NavLink } from 'react-router-dom';
function Navbar() {
return (
<nav>
{/* Basic Link */}
<Link to="/">Home</Link>
<Link to="/about">About</Link>
{/* NavLink - adds active class automatically */}
<NavLink
to="/"
className={({ isActive }) => isActive ? 'active' : ''}
>
Home
</NavLink>
<NavLink
to="/about"
style={({ isActive }) => ({
fontWeight: isActive ? 'bold' : 'normal',
color: isActive ? 'blue' : 'gray'
})}
>
About
</NavLink>
</nav>
);
}
⚠️ Link vs <a> Tag
Always use <Link> for internal navigation. Regular <a> tags cause full page reloads, losing React state and performance benefits.
Dynamic Routes (URL Parameters)
import { useParams } from 'react-router-dom';
// Route definition
<Route path="/users/:userId" element={<UserProfile />} />
<Route path="/posts/:postId/comments/:commentId" element={<Comment />} />
// Component accessing params
function UserProfile() {
const { userId } = useParams();
return <h1>User ID: {userId}</h1>;
}
// Multiple params
function Comment() {
const { postId, commentId } = useParams();
return (
<div>
<p>Post: {postId}</p>
<p>Comment: {commentId}</p>
</div>
);
}
// Linking with params
<Link to="/users/123">View User 123</Link>
<Link to={`/users/${user.id}`}>View {user.name}</Link>
Programmatic Navigation
import { useNavigate } from 'react-router-dom';
function LoginForm() {
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
const success = await loginUser(credentials);
if (success) {
// Navigate to dashboard
navigate('/dashboard');
// Navigate with replace (no back button)
navigate('/dashboard', { replace: true });
// Go back
navigate(-1);
// Go forward
navigate(1);
}
};
return <form onSubmit={handleSubmit}>...</form>;
}
// Navigate with state
function ProductCard({ product }) {
const navigate = useNavigate();
const handleClick = () => {
navigate(`/products/${product.id}`, {
state: { fromHome: true, product }
});
};
return <button onClick={handleClick}>View Details</button>;
}
Nested Routes
import { Outlet } from 'react-router-dom';
// Layout component with Outlet
function DashboardLayout() {
return (
<div className="dashboard">
<Sidebar />
<main>
<Outlet /> {/* Child routes render here */}
</main>
</div>
);
}
// Route configuration
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
{/* Nested routes */}
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<DashboardHome />} />
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
</BrowserRouter>
);
}
// URLs:
// /dashboard → DashboardLayout + DashboardHome
// /dashboard/profile → DashboardLayout + Profile
// /dashboard/settings → DashboardLayout + Settings
Query Parameters
import { useSearchParams } from 'react-router-dom';
function SearchPage() {
const [searchParams, setSearchParams] = useSearchParams();
// Read query params
const query = searchParams.get('q') || '';
const page = parseInt(searchParams.get('page')) || 1;
const sort = searchParams.get('sort') || 'newest';
// Update query params
const handleSearch = (newQuery) => {
setSearchParams({ q: newQuery, page: 1 });
};
const handlePageChange = (newPage) => {
setSearchParams({ q: query, page: newPage, sort });
};
return (
<div>
<input
value={query}
onChange={(e) => handleSearch(e.target.value)}
/>
<p>Page: {page}</p>
<button onClick={() => handlePageChange(page + 1)}>Next</button>
</div>
);
}
// URL: /search?q=react&page=2&sort=newest
Protected Routes
import { Navigate, useLocation } from 'react-router-dom';
// Protected route wrapper
function ProtectedRoute({ children }) {
const { user } = useAuth(); // Your auth hook
const location = useLocation();
if (!user) {
// Redirect to login, save attempted URL
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
}
// Usage in routes
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
</Routes>
// Redirect back after login
function Login() {
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname || '/';
const handleLogin = async () => {
await login();
navigate(from, { replace: true });
};
}
404 Not Found Page
function NotFound() {
return (
<div>
<h1>404 - Page Not Found</h1>
<Link to="/">Go Home</Link>
</div>
);
}
// Catch-all route (must be last)
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<NotFound />} />
</Routes>
Location State
import { useLocation } from 'react-router-dom';
// Passing state
<Link to="/checkout" state={{ items: cartItems }}>
Checkout
</Link>
// Receiving state
function Checkout() {
const location = useLocation();
const { items } = location.state || { items: [] };
return (
<div>
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}
</div>
);
}
🎯 React Router Best Practices
- ✓ Always use Link/NavLink for internal navigation
- ✓ Use nested routes for shared layouts
- ✓ Handle 404 with a catch-all route
- ✓ Use useNavigate for programmatic navigation
- ✓ Protect sensitive routes with auth checks
- ✓ Use query params for filterable/shareable state
- ✓ Consider React Router's data loading features (loader, action)