DEV Community

Alifa Ara Heya
Alifa Ara Heya

Posted on • Edited on

Introduction to React Router v7 (Data Router API)

Needs major update! Don't follow it!
React Router v7 introduced the Data Router API, a declarative and more powerful way to define routes, load data, handle actions, and manage layouts. Unlike the traditional approach using BrowserRouter, Routes, and Route, the data router approach uses functions like createBrowserRouter and RouterProvider to define routing, layouts, nested routes, and more.

Use this guide if:

  • You want a clean, nested layout structure
  • You plan to use loaders, actions, or error boundaries
  • You are using Vite/React and want a modern routing setup

πŸš€ Install React Router

npm i react-router
Enter fullscreen mode Exit fullscreen mode

πŸ—‚οΈ Create routes/index.tsx

You can use either Component or element, but with the Data Router API, prefer Component.

import App from "@/App";
import Tasks from "@/pages/Tasks";
import User from "@/pages/User";
import UserDetails from "@/pages/UserDetails";
import NotFound from "@/pages/NotFound";
import { createBrowserRouter } from "react-router-dom";

const router = createBrowserRouter([
  {
    path: "/",
    Component: App,
    children: [
      {
        index: true,
        element: <Tasks />, // Show on homepage
      },
      {
        path: "tasks",
        element: <Tasks />,
      },
      {
        path: "users",
        element: <User />,
      },
      {
        path: "users/:id",
        element: <UserDetails />,
      },
      {
        path: "*",
        element: <NotFound />, // 404 Page
      },
    ],
  },
]);

export default router;
Enter fullscreen mode Exit fullscreen mode

🧡 Setup main.tsx

Make sure to use RouterProvider with the created router. If you're using state management (like Redux) or a UI library (like shadcn), wrap accordingly.

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import { Provider } from "react-redux";
import { store } from "./redux/store";
import { RouterProvider } from "react-router-dom";
import router from "./routes/index";
import { ThemeProvider } from "./providers/theme-provider";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
      <Provider store={store}>
        <RouterProvider router={router} />
      </Provider>
    </ThemeProvider>
  </StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

🧩 Define Layout with <Outlet /> in App.tsx

Child routes render wherever <Outlet /> is used. Without it, nothing will render.

import { Outlet } from "react-router-dom";
import Navbar from "@/components/layout/Navbar";

function App() {
  return (
    <>
      <Navbar />
      <Outlet />
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

πŸ§ͺ Example Page Component - Tasks

const Tasks = () => {
  return (
    <div>
      <h1>This is Tasks component</h1>
    </div>
  );
};

export default Tasks;
Enter fullscreen mode Exit fullscreen mode

πŸ” Dynamic Route Example - users/:id

import { useParams } from "react-router-dom";

const UserDetails = () => {
  const { id } = useParams();
  return <div>User ID: {id}</div>;
};

export default UserDetails;
Enter fullscreen mode Exit fullscreen mode

❌ 404 Page Example

const NotFound = () => {
  return <h1>404 - Page Not Found</h1>;
};

export default NotFound;
Enter fullscreen mode Exit fullscreen mode

πŸ“ Key Notes

  • βœ… Use index: true to render default content on /.
  • βœ… Include <Outlet /> in your layout to render child routes.
  • βœ… Use path: "*" for fallback 404 pages.
  • βœ… Use useParams() to extract dynamic values like :id.
  • βœ… You can share state/context (Redux, Theme) using top-level providers.

πŸ“¦ What You’ve Built So Far

  • βœ… Modern nested routing with layout (App.tsx)
  • βœ… Default (index) route
  • βœ… 404 not found handler
  • βœ… Dynamic route (users/:id)

βž• What's Next (Optional Add-ons)

1. πŸ“€ Loader and Action Route Example

import { createBrowserRouter } from "react-router-dom";
import Tasks from "@/pages/Tasks";

const router = createBrowserRouter([
  {
    path: "/tasks",
    element: <Tasks />, // fallback to "element" usage here for loader/action
    loader: async () => {
      const res = await fetch("/api/tasks");
      return res.json();
    },
    action: async ({ request }) => {
      const formData = await request.formData();
      return fetch("/api/tasks", {
        method: "POST",
        body: formData,
      });
    },
  },
]);
Enter fullscreen mode Exit fullscreen mode

2. πŸ” Protected Routes Full Example

import { createBrowserRouter } from "react-router-dom";
import ProtectedLayout from "@/layouts/ProtectedLayout";
import Profile from "@/pages/Profile";
import Login from "@/pages/Login";

const router = createBrowserRouter([
  {
    path: "/login",
    element: <Login />,
  },
  {
    path: "/dashboard",
    Component: ProtectedLayout,
    children: [
      {
        path: "profile",
        element: <Profile />,
      },
    ],
  },
]);
Enter fullscreen mode Exit fullscreen mode

3. 🧱 Separate Layouts Example

import { createBrowserRouter } from "react-router-dom";
import MainLayout from "@/layouts/MainLayout";
import AdminLayout from "@/layouts/AdminLayout";
import Home from "@/pages/Home";
import About from "@/pages/About";
import AdminDashboard from "@/pages/AdminDashboard";

const router = createBrowserRouter([
  {
    path: "/",
    Component: MainLayout,
    children: [
      { index: true, element: <Home /> },
      { path: "about", element: <About /> },
    ],
  },
  {
    path: "/admin",
    Component: AdminLayout,
    children: [{ path: "dashboard", element: <AdminDashboard /> }],
  },
]);
Enter fullscreen mode Exit fullscreen mode

4. 🧭 Nested Routes Example

import { createBrowserRouter } from "react-router-dom";
import UserLayout from "@/layouts/UserLayout";
import UserList from "@/pages/UserList";
import UserDetails from "@/pages/UserDetails";

const router = createBrowserRouter([
  {
    path: "/users",
    Component: UserLayout,
    children: [
      { index: true, element: <UserList /> },
      { path: ":id", element: <UserDetails /> },
    ],
  },
]);
Enter fullscreen mode Exit fullscreen mode

Top comments (0)