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 new
data 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 above
data 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 newdata 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
- 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>
);
}
- 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 withRouterProvider
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:
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.
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.
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:
Eliminating manual data fetching: Instead of using useEffect to fetch data in chunks, useDataLoader simply takes care of it.
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.
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.