DEV Community

Cover image for A brief intro about loaders in react router
Shaan Alam
Shaan Alam

Posted on

A brief intro about loaders in react router

Hi. In the ever-evolving field of web-development, user experience is the top priority. As our web app grows more complex and data-intensive, we face challenges of efficiently handling and loading data to ensure seamless user experience.

A few days back I was working on a personal project, where I need to fetch data from the back-end based on different routes in my React App. I wanted to basically render each note on a different route. So I created dynamic routes. The routes was created with the note's unique ID. Suppose a note has ID 1, to it will be rendered on /notes/1 route.

My First approach was to create a Note component and then obtain the unique ID from the params. And then I could use this ID to fetch the data from my server. This approach had me encounter several problems.

Problems faced

  • Inefficient data loading: Without proper handling, & fetching data for dynamic route can lead to multiple server requests which are unnecessary. This in turn can increase the server load.

  • Data inconsistency: As I was navigating between different routes, the data related to each route was not updated properly.

  • Inefficiency in handling state managment: Managing the loading state and displaying the approprite UI was complex in this case because I was dealing with multiple dynamic routes simultaneously.

Solution

After researching, I cam across data loaders in react-router-dom. After reading docs, I came to understand about data loaders and how they are useful in this particular scenario. In this blog I will teach you what are data loaders and how they work in react-router!3

What are loaders?

Loaders are just functions which are used to handle the loading of the data while you are navigating between the pages of the website. Imagine you are browsing a website. When you browse to a new page, a loader or spinner is displayed to show that the data is being fetched until the new page loads. Loaders in react router work similarly.

What are we going to build.

We're gonna build a simple project where will dispplay the posts (fetched from an API) on a page. And each post will have it's own route and will be displayed there. It's going to look something like this -

React Router

Let's Code!

Creating React App and installing react-router-dom

npx create-react-app loader-example
cd loader-example
npm install loader-example
Enter fullscreen mode Exit fullscreen mode

Basic Setup

We willl be building simple components to fetch data from an API and show it in the UI. We will create three routes home, /posts, /posts/:idinside the parent route /

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

const Layout = () => {
  return (
    <>
      <Link to="/home">Home</Link>
      <Link to="/posts">Posts</Link>
      <div>
        <Outlet />
      </div>
    </>
  );
};

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<Layout />}>
      <Route index path="/home" element={<Home />} />
      <Route path="/posts" element={<Posts />}></Route>
      <Route path="/posts/:id" element={<Post />} />
    </Route>
  )
);
Enter fullscreen mode Exit fullscreen mode

First, we will create Browser Router by creating routes inside it using the createBrowserRouter and createRoutesFromElements functions like this.

Just creating the router won't help, we have to pass this router inside the RouterProvider component inside the App Component.

import {
  createBrowserRouter,
  createRoutesFromElements,
} from "react-router-dom";

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<Layout />}>
      <Route index path="/home" element={<Home />} />
      <Route path="/posts" element={<Posts />}></Route>
      <Route path="/posts/:id" element={<Post />} />
    </Route>
  )
);

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

export default App;

Enter fullscreen mode Exit fullscreen mode

Building the components

Now we just have to build the Home and Posts component.

// Home.js
const Home = () => {
  return (
    <div>
      <p>Home page</p>
    </div>
  )
}

export default Home;
Enter fullscreen mode Exit fullscreen mode
const api = "https://jsonplaceholder.typicode.com/posts";

const Posts = () => {
  // Posts Component
};

export default Data;

export const dataLoader = async () => {
  const res = await fetch(api);
  const jsonResult = await res.json();

  return jsonResult;
};

Enter fullscreen mode Exit fullscreen mode

In the Posts component, we will also create a data loader function and export it. In this function we will actually fetch the results from an external API and return it. Later, we will use this function in App.js to mention the loader in the routes.

The loader will fetch the result just before the Posts component renders on the screen, so that it has the necessary data to show in the UI.

Now, let's complete the Posts component.

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

const api = "https://jsonplaceholder.typicode.com/posts";

const Data = () => {
  const result = useLoaderData();
  const navigation = useNavigation();

  if (navigation.state === "loading") {
    return <h1>Loading!</h1>;
  }

  return (
    <div>
      {result.map((res) => (
        <div key={res.id}>
          <Link to={`/posts/${res.id}`}>
            <h1>{res.title}</h1>
          </Link>
          <p>{res.body}</p>
        </div>
      ))}
    </div>
  );
};

export default Data;

export const dataLoader = async () => {
  const res = await fetch(api);
  const jsonResult = await res.json();

  return jsonResult;
};

Enter fullscreen mode Exit fullscreen mode

We will use the useLoaderData() hook to get the result from the loader. Also using the useNavigation() hook, we can check the state of the loader and display some kind of spinner in the UI to tell the user that deta is being fetched in the background. However, for the sake of simplicity I just rendered a heading in the UI for this puprose.

Now, we just have to build the post component which is very simple. We just have to create a simple component which has a loader which will be used to fetch a single post from the external API. The response of the API can be used inside the component using the useLoaderData() hook.

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

const api = "https://jsonplaceholder.typicode.com/posts";

export const postLoader = async ({ params }) => {
  const res = await fetch(`${api}/${params.id}`);
  const resJson = await res.json();

  return resJson;
};

const Post = () => {
  const result = useLoaderData();
  return (
    <div>
      <h1>
        {result.id} - {result.title}
      </h1>
    </div>
  );
};

export default Post;

Enter fullscreen mode Exit fullscreen mode

Final router changes

Now we just have to do one more change in the App component. We will have to pass the loaders function we created inside the Posts and Post components in their respective routes.

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<Layout />}>
      <Route index path="/home" element={<Home />} />
      <Route path="/posts" element={<Posts />} loader={dataLoader} />
      <Route path="/posts/:id" element={<Post />} loader={postLoader} />
    </Route>
  )
);
Enter fullscreen mode Exit fullscreen mode

And now we are done!

And this is how data fetching in react-router-dom is made easy using Data Loaders.

Conclusion

I hope you enjoyed this tutorial. If you think I made a mistake somewhere let me know in the comment section.

Github Repo - https://github.com/shaan-alam/react-router-loaders-example

Live Demo - https://react-router-loaders-example.vercel.app/

My Socials

Twitter - https://twitter.com/shaancodes

Instagram - https://www.instagram.com/shaancodes/

GitHub - https://github.com/shaan-alam/

Top comments (2)

Collapse
 
dawdison2008 profile image
Dawid Błaszczak

Hi, first of all thank you for the article it's very readable and understanable. I have a little problem, with choosing react query to fetch data or do it with loader as shown above.
I would be gratefull for your aswers : -).

Collapse
 
bytexbender profile image
b'

thx for this man