React Router provides client-side routing with nested routes and Outlet for layout composition, hooks for navigation (useNavigate, useParams), and data APIs (loaders/actions) for fetching data before rendering.
Routes nest inside parent routes. Parent renders <Outlet /> where child content appears — the standard pattern for shared layouts.
useNavigate for programmatic navigation, useParams for URL segments, useSearchParams for query strings, useLocation for current path.
loader functions fetch data before render, action functions handle mutations — moves data fetching from components to the routing layer.
BrowserRouter (clean URLs, needs server config), HashRouter (hash URLs, static hosting), MemoryRouter (tests/non-browser).
Check auth in loaders (redirect if unauthorized) or wrap routes in guard components that conditionally render or redirect.
React doesn't include routing — React Router is the standard library for client-side navigation. It maps URL paths to components, enabling single-page application navigation without full page reloads.
<BrowserRouter> wraps the app and uses the HTML5 History API for clean URLs (/about, /users/123)<Routes> contains route definitions<Route path="/about" element={<About />} /> maps a URL path to a component<Link to="/about"> and <NavLink to="/about"> render anchor tags that navigate without page reload. NavLink adds active styling automatically<Outlet /> renders the matched child route — this is how nested layouts workRoutes can be nested to create layout hierarchies. A parent route renders a layout component with <Outlet />, and child routes fill the outlet:
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<Overview />} />
<Route path="settings" element={<Settings />} />
</Route>DashboardLayout contains shared navigation and renders <Outlet /> where child content appears. This pattern eliminates layout duplication.
useNavigate() — returns a function for programmatic navigation: navigate('/login') or navigate(-1) to go backuseParams() — reads dynamic URL segments: /users/:id → { id: '123' }useSearchParams() — reads and writes query string parameters: ?page=2&sort=nameuseLocation() — returns the current location object (pathname, search, hash, state)React Router v6.4 introduced data-driven routing inspired by Remix:
loader functions fetch data before a route renders — no loading spinners inside componentsaction functions handle form submissions and mutationsuseLoaderData() accesses the data returned by the loader<Form> component submits to the route's action functionuseNavigation() tracks in-progress navigations for global loading indicatorsThis pattern moves data fetching from components to the routing layer, eliminating fetch-on-render waterfalls.
BrowserRouter — uses History API, requires server to serve index.html for all routesHashRouter — uses URL hash (#/about), works on static hosting without server configMemoryRouter — keeps URL in memory, useful for tests and non-browser environmentsRedirect unauthorized users by checking auth state in a loader (return redirect('/login')) or by wrapping routes in a guard component that checks auth and renders either the child or a redirect.
React Router v6+ uses nested routes with Outlet for layout composition, hooks for navigation and URL reading, and optional data APIs (loaders/actions) for data-driven routing. The data APIs move data fetching from components to routes, eliminating loading waterfalls. Nested routes with Outlet are the idiomatic way to share layouts across related pages.
Fun Fact
React Router v7 (released 2024) is essentially Remix merged into React Router. The Remix framework team decided that instead of maintaining two projects, they would bring Remix's data-loading patterns directly into React Router, effectively making every React Router app a potential Remix app.