React Router Setup – Complete Guide
Learn how to set up React Router DOM in React applications. Complete guide with routes, navigation, protected routes, and nested routes. Step-by-step tutorial.
When I first started building React applications, I thought routing would be simple. Just show different components based on the URL, right? Then I had to implement protected routes, nested layouts, route parameters, and handle 404 pages. That's when I realized that proper routing setup is crucial for building maintainable React applications.
React Router DOM is the de facto standard for routing in React applications. It enables client-side routing, which means navigation happens without full page refreshes—your app feels fast and responsive. But more importantly, it provides a declarative way to define your application's routes, handle navigation, and protect routes based on authentication status.
In this guide, I'll show you how I structure routing in production React applications. We'll cover basic route setup, protected routes (so unauthenticated users can't access certain pages), nested layouts (for shared navigation and sidebars), route parameters (for dynamic routes like /products/:id), and handling 404 pages. I'll also share some patterns I've learned that make routing more maintainable as your application grows.
Installation
npm install react-router-domBasic Router Setup
Setting up the router in your main app:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { Provider } from "react-redux";
import { store } from "./state/store";
import Login from "./pages/Auth/Login";
import Signup from "./pages/Auth/Signup";
import DashboardLayout from "./components/DashboardLayout";
import Home from "./pages/Home";
import Products from "./pages/Products/Products";
import AddProduct from "./pages/Products/AddProduct";
import EditProduct from "./pages/Products/EditProduct";
function App() {
return (
<Provider store={store}>
<BrowserRouter>
<Routes>
{/* Public routes */}
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
{/* Protected routes with layout */}
<Route element={<DashboardLayout />}>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
<Route path="/products/add" element={<AddProduct />} />
<Route path="/products/edit/:id" element={<EditProduct />} />
</Route>
{/* 404 route */}
<Route path="*" element={<div>404 - Page Not Found</div>} />
</Routes>
</BrowserRouter>
</Provider>
);
}
export default App;Using Outlet for Nested Routes
Creating a layout component with Outlet:
import { Outlet, useNavigate } from "react-router-dom";
import SideBar from "./SideBar";
import MainContent from "./MainContent";
export default function DashboardLayout() {
const [pageTitle, setPageTitle] = useState("");
const navigate = useNavigate();
const context = {
setPageTitle,
};
return (
<div className="min-h-screen bg-gray-100">
<div className="flex">
<SideBar />
<MainContent>
<Outlet context={context} />
</MainContent>
</div>
</div>
);
}Navigation in Components
Using useNavigate for programmatic navigation:
import { useNavigate, useParams } from "react-router-dom";
function Products() {
const navigate = useNavigate();
const handleAdd = () => {
navigate("/products/add");
};
const handleEdit = (id: string) => {
navigate("/products/edit/" + id);
};
const handleBack = () => {
navigate("/products");
};
return (
<div>
<button onClick={handleAdd}>Add Product</button>
<button onClick={() => handleEdit("123")}>Edit Product</button>
<button onClick={handleBack}>Back</button>
</div>
);
}
// Using route parameters
function EditProduct() {
const { id } = useParams<{ id: string }>();
return <div>Editing product: {id}</div>;
}Using Link Component
Creating navigation links:
import { Link, NavLink } from "react-router-dom";
function SideBar() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/products">Products</Link>
<Link to="/categories">Categories</Link>
{/* Active link styling */}
<NavLink
to="/products"
className={({ isActive }) =>
isActive ? "active-link" : "inactive-link"
}
>
Products
</NavLink>
</nav>
);
}Protected Routes
Implementing route protection:
import { Navigate, Outlet } from "react-router-dom";
import { useSelector } from "react-redux";
function ProtectedRoute() {
const isAuthenticated = useSelector((state: RootState) => state.auth.isAuthenticated);
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
}
// Usage
<Route element={<ProtectedRoute />}>
<Route path="/products" element={<Products />} />
<Route path="/categories" element={<Categories />} />
</Route>Best Practices
- Use BrowserRouter for client-side routing
- Organize routes by feature or module
- Use Outlet for nested layouts
- Implement protected routes for authentication
- Use NavLink for active link styling
- Handle 404 routes properly
- Use route parameters for dynamic routes
Conclusion
React Router DOM provides powerful routing capabilities for React applications. With nested routes, protected routes, and programmatic navigation, you can create complex navigation structures for inventory management systems and other React applications.
Related Articles
React Hook Form with Zod Validation: Complete Guide
Learn how to implement form validation in React using React Hook Form and Zod.
Redux Toolkit RTK Query: Complete Guide for React State Management
Learn how to use Redux Toolkit RTK Query for API data fetching and state management.
TanStack Table Implementation in React: Complete Guide
Build advanced data tables with sorting, filtering, pagination, and row selection.
TypeScript with React: Best Practices and Patterns
Learn TypeScript best practices for React development with type definitions and interfaces.