MENU
Routers
At the core of every React Router application is a low-level <Router> component that the higher-level routers below are built on top of. Most apps never use <Router> directly – reach for one of the declarative routers below, or for the data-router APIs described further down this page.
There are a few higher-level, special-purpose versions of <Router> typically used by apps: <BrowserRouter>, <HashRouter>, <MemoryRouter>, and <StaticRouter>, each covered on its own page next. You wrap your whole app in one of these, then describe your pages underneath with <Routes> and <Route>. This style is called declarative mode, and it's the simplest way to get started – it's what the rest of this tutorial section mostly uses.
Data routers
For anything beyond a small app, React Router's own documentation now recommends a different, more capable style: build your route tree as a plain array of route objects with createBrowserRouter(), then render it with <RouterProvider>. Each route object can carry a "loader" (and an "action") right alongside its "path" and "element", so data fetching is tied directly to the route that needs it instead of being wired up separately in each component with effects. See Loaders and Actions for a deeper dive into this route-object shape and the full family of hooks it unlocks.
Note the two different import sources below: createBrowserRouter comes from the main "react-router" package, while <RouterProvider> specifically comes from "react-router/dom".
import { createBrowserRouter } from "react-router";
import { RouterProvider } from "react-router/dom";
import { useLoaderData } from "react-router";
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
children: [
{ index: true, element: <Home /> },
{
path: "about",
element: <About />,
loader: () => fetch("/api/about").then((r) => r.json()),
},
],
},
]);
function About() {
let data = useLoaderData();
return <h2>{data.title}</h2>;
}
export default function App() {
return <RouterProvider router={router} />;
}Hooks like useLoaderData() and useFetcher() (for loading or submitting data without a full navigation) only work underneath a data router like this one – they don't work inside a plain <BrowserRouter><Routes> tree. The same is true of useBlocker(), covered later in this section. Declarative mode (<BrowserRouter>/<Routes>/<Route>) and data routers both still use the same <Route>, path syntax, and hooks for reading the URL (useParams(), useLocation(), etc.) – the difference is only in how the route tree is built and whether it can own data loading.