Routing with React Router v6.4

ยท

6 min read

Routing with React Router v6.4

Explore enhanced routing capabilities and data fetch simplifications introduced in React Router v6.4.

React Router, the main tool for managing traffic in React applications has released version 6.4, with many enhancements and changes. With the recent release of React Router, there have been significant changes to the framework, improving the user experience and simplifying the development process

We'll talk about the Benefits and Enhancements of v6.4 later in the blog.

In v6.4, 4 new routers were introduced.

  • createBrowserRouter

  • createMemoryRouter

  • createStaticRouter

  • createHashRouter

In this article, we'll study about the createBrowserRouter and how it differs from the traditional<BrowserRouter>

Only these new routers support the newdata APIs.

There are a ton of new data APIs:

  • route.lazy

  • route.loader

  • route.shouldRevalidate

  • route.handle

  • useActionData

  • useAsyncError

  • useAsyncValue

  • useLoaderData

  • useMatches

  • useNavigation

  • useRevalidator

  • useRouteError

  • useRouteLoaderData

And many more...!

In this article, we'll briefly study about route.loader & useLoaderData

So, if you want to use the abovedata apis, which are by the way quite helpful, then you need to migrate from <BrowserRouter> to one of the new routers.

Picking a Router

The React Router Official Docs suggests that:

  • createBrowserRouter: All web projects use createBrowserRouter. It makes use of full URLs and is better for SEO, and of course, it supports the new data apis

  • createMemoryRouter : createMemoryRouter creates a router that manages its own history stack in memory. This simplifies the process of testing components that use React Router by allowing you to isolate your components from the browser's history stack, making it easier to test them in a controlled environment.

  • createHashRouter : If for some reason you can't use the full URL, createHashRouter can be a suitable fit.

  • createStaticRouter : createStaticRouter creates a router for server-side rendering (SSR). SSR is a technique for rendering React components on the server, rather than on the client. This can improve the performance of your application, especially for initial page loads.

Let's dive straight into the code!

Basic Routing Setup

  1. In Previous versions using browserRouter App.js ๐Ÿ‘‡
import * as React from "react";
import { BrowserRouter, Route, Link, Routes } from "react-router-dom";

export default function App() {
  return (
    <BrowserRouter>
      <main>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/user">User</Link>
            </li>
            <li>
              <Link to="/contact">Contact</Link>
            </li>
          </ul>
        </nav>

        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/user" element={<User />} />
          <Route path="/contact" element={<Contact />} />
        </Routes>
      </main>
    </BrowserRouter>
  );
}
  1. In the Latest v6.4 using createBrowserRouter

Method 1

App.js ๐Ÿ‘‡

import {
  createBrowserRouter,
  RouterProvider,
  Route,
  createRoutesFromElements,
} from "react-router-dom";
import "./App.css";
import { RootLayout } from "./components/RootLayout";

export default function App() {
  const router = createBrowserRouter(
    createRoutesFromElements(
      <Route path="/" element={<RootLayout />}>
        <Route index element={<Home />} />
        <Route path="/user" element={<User />} />
        <Route path="/contact" element={<Contact />} />
      </Route>
    )
  );

  return <RouterProvider router={router} />;
}

RootLayout.jsx ๐Ÿ‘‡

import { Outlet , Link} from "react-router-dom";

export const RootLayout = () => {
  return (
  <main>
    <nav>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/user">User</Link>
          </li>
          <li>
            <Link to="/contact">Contact</Link>
          </li>
        </ul>
      </nav>

    {/* Components will be rendered here */}
    <Outlet />

    </main>)
};

Let's understand the above code setup

  • App.js : createBrowserRouter function and wraps the application with RouterProvider to provide routing context.

  • RootLayout.jsx : This file defines the RootLayout component, which acts as the main layout for the application. It renders the common elements, such as the header and navigation bar, and provides an Outlet component to dynamically render the child routes.

  • createRoutesFromElements : This function from React Router v6.4 is used to create a nested routing configuration. It allows you to define nested routes within a parent route, enabling a hierarchical routing structure.

There's an alternate way of defining createBrowserRouter too:

Method 2:

export default function App() { const router = createBrowserRouter([ { path: "/", element: <RootLayout />, children: [ { path: "/", element: <Home />, }, { path: "user", element: <User />, }, { path: "contact", element: <Contact />, }, ], }, ]); return <RouterProvider router={router} />; }

Both methods of defining createBrowserRouter are valid. The choice between them depends on your specific needs and preferences.

Considerations :

  • Conciseness: Method 2 is generally more concise for smaller routing configurations.

  • Readability: Both methods are relatively readable, but method 1 may be slightly more readable for complex routing structures due to its declarative syntax.

  • Maintenance: Both methods are generally maintainable, but method 1 may be easier to maintain for complex routing structures due to its declarative syntax and clear organization.

Now it's time to learn more about the Benefits & Enhancements!

Benefits & Enhancements:

  1. Data APIs Integration: React Router v6.4 introduces data APIs that allow you to manage data fetching, loading, and synchronization within your routing logic. These APIs provide a convenient way to handle data dependencies and ensure that your routes have the data they need when they render.

  2. Declarative API: React Router v6.4 adopts a declarative API, making it easier to define and manage routing configurations. Instead of using imperative Route components, you can now define routes using a declarative syntax, enhancing readability and maintainability.

  3. Nested Routes: The new API supports nested routes and route groups, enabling you to organize your routing structure more effectively. Nested routes allow you to create hierarchical routing structures, while route groups let you group related routes and share configuration options.

    Now, its time to study the new Data API: loader & useDataLoader

    The useDataLoader hook simplifies data fetching in React Router v6.4 by handling data loading and synchronization directly within the routing configuration.

    This means you don't need to manually fetch data in individual components, reducing the need for useEffect and useState hooks.

    Let's take a look at the code

    User.jsx :

    
     import { useLoaderData } from "react-router-dom";
    
     export const User = () => {
       const userData = useLoaderData();
    
       return (
         <div>
           <h1>User</h1>
           <p>Name: {userData.name}</p>
           <p>Email: {userData.email}</p>
         </div>
       );
     };
    
     export const userDataLoader = async () => {
       const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
       const data = await response.json();
       return data;
     };
    

    App.js:

     export default function App() {
       const router = createBrowserRouter([
         {
           path: "/",
           element: <RootLayout />,
           children: [
             {
               path: "/",
               element: <Home />,
             },
             {
               path: "user",
               element: <User />,
               loader: userDataLoader,
             },
             {
               path: "contact",
               element: <Contact />,
             },
           ],
         },
       ]);
    
       return <RouterProvider router={router} />;
     }
    

    This helps in terms of receiving data and being ready when we hit the road:

    1. Eliminating manual data fetching: Instead of using useEffect to fetch data in chunks, useDataLoader simply takes care of it.

    2. Avoid re-reference due to data fetching: By fetching data directly in the routing process, useDataLoader ensures that components are not re-referenced whenever data changes because data is loaded and available to components through routing references, not component status.

    3. Simplifying state management: Since useDataLoader handles data fetching and synchronization, you do not need to use useState hooks on components that rely on this data to handle data state.

      Thatโ€™s it for this blog.

      Summary of topics covered :

      1. Differences in routing configuration:

      React Router v6.4 introduces a more declarative and composable approach to routing than previous versions. The createBrowserRouter function provides an explicit and modular way to define routing configuration.

      2. Data API and useDataLoader:

      React Router v6.4 introduces data APIs that integrate data capture and synchronization within the routing logic. These APIs only work with other routers.

      3. Benefits of useDataLoader:

      Finishes brings manual data in components. Reduces resubmissions due to data changes & simplifies data status management. It encourages a declarative and centralized approach to information management. Provides data for the route element before it is defined.

      I hope you enjoyed reading this blog! If you find this blog informative and helpful, please give it a thumbs up and share it with your fellow developers. If youโ€™d like to see part two of this blog, feel free to leave a comment. I am all ears for your thoughts.

ย