React Router basics
By Flavio Copes
A quickstart to React Router in your React app, covering installation, Routes and Route, navigation with Link and useNavigate, and URL parameters.
Reach Router (@reach/router) used to be a simple way to do routing in a React app. That project is no longer the recommended router — it was superseded by React Router, which is the surviving library (the old Reach migration docs point you there).
Here’s a 5 minutes tutorial to get the basics of React Router.
Installation
First, install it using
npm install react-router
(If you’re starting a new app, scaffold with Vite — npm create vite@latest — rather than create-react-app.)
Next, import what you need in your project.
import { BrowserRouter, Routes, Route, Link, useNavigate, useParams } from 'react-router'
Basic usage
I use it in the top-level React file, wrapping the app in BrowserRouter and listing routes with Routes / Route:
import { createRoot } from 'react-dom/client'
import { BrowserRouter, Routes, Route } from 'react-router'
createRoot(document.getElementById('root')).render(
<BrowserRouter>
<Routes>
<Route path="/" element={<Form />} />
<Route path="/private-area" element={<PrivateArea />} />
</Routes>
</BrowserRouter>
)
The path prop sets the URL for that route. The element prop is the component (or JSX) to render when it matches.
In other words, when I type that path in the browser URL bar, React Router shows that specific component to me.
The / path is the index route, and shows up when you don’t set a URL / path beside the app domain. The “home page”, in other words.
For apps that need loaders, actions, and nested data routing, React Router also has createBrowserRouter + RouterProvider. The BrowserRouter + Routes style above is enough for a short routing intro.
The default route (404)
When a user visits a URL that does not match any route, you can add a catch-all route and display a nice “404” message:
<Routes>
<Route path="/" element={<Form />} />
<Route path="/private-area" element={<PrivateArea />} />
<Route path="*" element={<NotFound />} />
</Routes>
Programmatically change the route
Use the useNavigate hook to programmatically change the route in your app:
import { useNavigate } from 'react-router'
function LoginButton() {
const navigate = useNavigate()
return (
<button onClick={() => navigate('/private-area')}>
Go to private area
</button>
)
}
Link to routes in JSX
Use the Link component to link to your routes using JSX:
import { Link } from 'react-router'
<Link to="/">Home</Link>
<Link to="/private-area">Private Area</Link>
URL parameters
Add parameters using the :param syntax:
<Routes>
<Route path="/users/:userId" element={<User />} />
</Routes>
Now in this hypothetical User component we can get the userId with useParams:
import { useParams } from 'react-router'
const User = () => {
const { userId } = useParams()
return <p>User {userId}</p>
}
Nested routes
I showed you how routes can be defined in this way in your top level React file:
<Routes>
<Route path="/" element={<Form />} />
<Route path="/private-area" element={<PrivateArea />} />
</Routes>
You can define nested routes. The parent renders an <Outlet /> where child routes appear:
import { Routes, Route, Outlet } from 'react-router'
function PrivateArea() {
return (
<div>
<h1>Private area</h1>
<Outlet />
</div>
)
}
<Routes>
<Route path="/" element={<Form />} />
<Route path="/private-area" element={<PrivateArea />}>
<Route path=":userId" element={<User />} />
</Route>
</Routes>
So now you can have your /private-area/23232 link point to the User component, with userId set to 23232.
To show something at /private-area itself (with no extra segment), add an index route:
<Route path="/private-area" element={<PrivateArea />}>
<Route index element={<PrivateAreaDashboard />} />
<Route path=":userId" element={<User />} />
</Route>
That’s enough to get routing working. For loaders, actions, and the full data APIs, see the React Router docs.
Want me to talk about your product? You can sponsor this site.