React Router Data Fetching

Introduction

In the most recent versions of React Router we were given a set of very interesting primitives and many of them are related to data fetching.

In the past, we always made http requests after the component was mounted and dealt w…


This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Francisco Mendes

Introduction

In the most recent versions of React Router we were given a set of very interesting primitives and many of them are related to data fetching.

In the past, we always made http requests after the component was mounted and dealt with the loading and error status depending on the result of that request. That is, we only had two aspects into account, what and how we were going to fetch it. Now, we can think about when we want to fetch the data and the approach we can do is at the route level.

Basically, as soon as the user navigates to a new route, data loading and rendering is done in parallel.

Assumed knowledge

The following would be helpful to have:

  • Basic knowledge of React
  • Basic knowledge of React Router

Getting Started

Project Setup

Run the following command in a terminal:

yarn create vite router-defer --template react
cd router-defer

Now we can install the necessary dependencies:

yarn add react-router-dom

Build the Components

The first step is to build the component that will contain the app's <Outlet />, still in this component we will create a function called randomIntFromInterval() that will generate a random number within an interval.

// @src/components/Layout.jsx
import { useCallback } from "react";
import { Link, Outlet, useNavigate } from "react-router-dom";

const Layout = () => {
  const navigate = useNavigate();

  const randomIntFromInterval = useCallback((min, max) => {
    return Math.floor(Math.random() * (max - min + 1) + min);
  }, []);

  const handlePostavigation = useCallback(() => {
    navigate(`/post/${randomIntFromInterval(6, 12)}`);
  }, [randomIntFromInterval]);

  return (
    <div>
      <nav>
        <Link to="/">Home</Link>
        <button onClick={handlePostavigation}>Random Post</button>
      </nav>

      <Outlet />
    </div>
  );
};

export default Layout;

As you may have noticed, the handlePostavigation() function will be responsible for generating a random integer that will be used as a route parameter. This parameter will be defined later in the router setup.

Create the Api Client

In today's example, we are going to consume two API endpoints JSONPlaceholder to get a specific post and its comments.

// @src/api.js
export const getPostById = async (postId) => {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${postId}`
  );
  return await response.json();
};

export const getCommentsByPostId = async (postId) => {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${postId}/comments`
  );
  return await response.json();
};

Build the Pages

With the Layout of our application created, we can start working on the pages. The first will be Home.jsx:

// @src/pages/Home.jsx
const Home = () => {
  return (
    <div>
      <h1>Home page</h1>
    </div>
  );
};

export default Home;

Now let's go to the most important page of this article, the one where we will use the loader to get the article and the respective comments from the loader.

But first of all let's reflect a little on what we really need, because with this approach, we can reduce the number of spinners in the app and we can enjoy the features of <Suspense>.

The most important content on the page would be the content of the post itself and the comments would be secondary, that is, we can fetch the post content in the loader, but then we use the defer function so that later we can fetch the comments.

Now comes the question, how could we later fetch the comments, the answer is quite simple, we can enjoy the benefits of the <Await> component that renders the deferred values and even handles errors automatically.

// @src/pages/RandomPost.jsx
import { Suspense } from "react";
import { defer, useLoaderData, Await } from "react-router-dom";

import { getCommentsByPostId, getPostById } from "../api";

export const postLoader = async ({ params }) => {
  const postId = params.postId;
  const post = await getPostById(postId);
  const commentsPromise = getCommentsByPostId(postId);
  return defer({ post, commentsPromise });
};

const RandomPost = () => {
  const { post, commentsPromise } = useLoaderData();

  return (
    <section>
      <h2>{post.title}</h2>
      <p>{post.body}</p>

      <Suspense fallback={<small>Loading Comments...</small>}>
        <Await resolve={commentsPromise}>
          {(comments) =>
            comments.map((comment) => (
              <span key={comment.id}>
                <small>{comment.body}</small>
                <br />
              </span>
            ))
          }
        </Await>
      </Suspense>
    </section>
  );
};

export default RandomPost;

In the loader() arguments we have access to some properties and one of them is the params object that in this case we need the postId, as well as what is returned from loader() is easily consumed by the useLoaderData() hook.

Router Setup

With the components and pages created, all that remains is to register our routes and assign the RandomPost page loader to the route.

// @src/App.jsx
import {
  Route,
  createBrowserRouter,
  createRoutesFromElements,
  RouterProvider,
} from "react-router-dom";

import Layout from "./components/Layout";
import HomePage from "./pages/Home";
import RandomPostPage, { postLoader } from "./pages/RandomPost";

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route element={<Layout />}>
      <Route index element={<HomePage />} />
      <Route
        path="/post/:postId"
        loader={postLoader}
        element={<RandomPostPage />}
      />
    </Route>
  )
);

export const App = () => {
  return <RouterProvider router={router} />;
};

Conclusion

As usual, I hope you enjoyed the article and that it helped you with an existing project or simply wanted to try it out.

If you found a mistake in the article, please let me know in the comments so I can correct it. Before finishing, if you want to access the source code of this article, I leave here the link to the github repository.


This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Francisco Mendes


Print Share Comment Cite Upload Translate Updates
APA

Francisco Mendes | Sciencx (2022-12-27T20:37:45+00:00) React Router Data Fetching. Retrieved from https://www.scien.cx/2022/12/27/react-router-data-fetching/

MLA
" » React Router Data Fetching." Francisco Mendes | Sciencx - Tuesday December 27, 2022, https://www.scien.cx/2022/12/27/react-router-data-fetching/
HARVARD
Francisco Mendes | Sciencx Tuesday December 27, 2022 » React Router Data Fetching., viewed ,<https://www.scien.cx/2022/12/27/react-router-data-fetching/>
VANCOUVER
Francisco Mendes | Sciencx - » React Router Data Fetching. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/12/27/react-router-data-fetching/
CHICAGO
" » React Router Data Fetching." Francisco Mendes | Sciencx - Accessed . https://www.scien.cx/2022/12/27/react-router-data-fetching/
IEEE
" » React Router Data Fetching." Francisco Mendes | Sciencx [Online]. Available: https://www.scien.cx/2022/12/27/react-router-data-fetching/. [Accessed: ]
rf:citation
» React Router Data Fetching | Francisco Mendes | Sciencx | https://www.scien.cx/2022/12/27/react-router-data-fetching/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.