React Router Cheatsheet

Migration and Pitfalls

Use this React Router reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

v5 to v6/v7 Migration

v5v6 / v7
<Switch><Routes>
component={X}element={<X />}
render={() => …}element={…}
Exact by default offExact by default on, use * or nesting for prefixes
exact propRemoved, paths match exactly unless nested
First match winsBest match wins (ranked)
useHistory()useNavigate()
history.push(p)navigate(p)
history.replace(p)navigate(p, { replace: true })
history.goBack()navigate(-1)
<Redirect to><Navigate to replace>
useRouteMatch()useMatch()
props.match.paramsuseParams()
withRouterHooks, or wrap it yourself
Nested <Route> anywhereNest in the route config, render <Outlet />
react-router-configBuilt in via route objects

v6 to v7 Migration

v6v7
react-router-domreact-router
json({ … })Return a plain object, or data()
defer({ … })Return bare promises
useTransition (router)useNavigation (renamed back in v6.4)
<Remix*> componentsThe same names in react-router
@remix-run/* packagesreact-router and @react-router/*
npx codemod react-router/2/upgrade-router     # community codemod for the import move

Common Mistakes

MistakeFix
Using data APIs under <BrowserRouter>Use createBrowserRouter + RouterProvider
Nested routes render nothingThe parent forgot <Outlet />
Every NavLink looks activeAdd end to the / link
useNavigate in an effect to redirectUse a loader redirect() or <Navigate>
Fetching in useEffect per componentMove it to a loader, kill the waterfall
Relative link goes somewhere oddCheck relative="route" vs "path"
Params are "42" not 42Params are always strings, convert and validate
Search filter spams historysetSearchParams(next, { replace: true })
No error boundaryAdd errorElement on the root route
Redirecting to a raw ?next= valueValidate it is a same-origin path
Basename included in toLeave it out, the router adds it
404 page returns HTTP 200Throw a Response with status: 404