Thursday, June 12, 2025

Data Loader With Dynamic Routes in React

In the post Data Loader in React Router we saw how to use loader function to fetch data for route component. In this post we'll see how to use data loader with dynamic routes in React.

Data Loading React Router Example

In this example we'll use a loader function to fetch data from API. For API call https://jsonplaceholder.typicode.com/posts resource is used which is a free fake API. In the example Bootstrap 5 is used for styling.

Route Configuration

src\components\routes\Route.js

import { createBrowserRouter } from "react-router";
import Home from "./home";
import NavigationNavLink from "./NavigationNavLink";
import ErrorPage from "./ErrorPage";
import PostList, {loader as PostLoader} from "./PostList";
import PostDetails, {loader as PostDetailsLoader} from "./PostDetails";
import PostLayout from "./PostLayout";

export const route = createBrowserRouter([
  {path: "/", element: <NavigationNavLink />, errorElement: <ErrorPage />,
   children: [
    {index: true, element: <Home /> },
    {path: "post", element: <PostLayout />,
     children:[
        {index: true, element: <PostList />, loader: PostLoader, hydrateFallbackElement: <h2>Loading...</h2>},
        {path: ":postId", element: <PostDetails />, loader: PostDetailsLoader, hydrateFallbackElement: <h2>Loading...</h2>},
     ]
    },
   ]
  },
])

As you can see there is a Navigation Menu component that is mapped to root route. Nested routes of root route are Home and PostLayout.

PostLayout again has nested routes for PostList to show all the posts and another as a dynamic route for showing details of a particular post by adding postId as path parameter to the URL.

Add this route configuration to RouteProvider.

<RouterProvider router={route}></RouterProvider>

Components used

Navigation Menu, Home and ErrorPage components remain as shown in this post- Data Loader in React Router.

src\components\routes\PostLayout.js

import { Outlet } from "react-router";
const PostLayout = () => {
  return(
    <div className="mx-2">
      <Outlet />
    </div>
  )
}

export default PostLayout;

There is just a <Outlet /> in this component to render the content for the child route components.

src\components\routes\PostList.js

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

const PostList = () => {
  const postData = useLoaderData();
  return(
    <>            
      <h2 className="text-info-emphasis text-center">Posts</h2>
      <ul className="list-group">
        {postData.map((post) =>
        <li className="list-group-item" key={post.id}>
            {post.id} <Link to={post.id.toString()}>{post.title}</Link>  
        </li>
        )}
      </ul>
    </>
  )
}

export default PostList


export async function loader(){
  const response = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=10');
  // check for any error
  if(!response.ok){
    // use Response object
    throw new Response("Failed to load data", { status: response.status });
  }else{
    const responseData = await response.json();
    return responseData;
  }
}

Some of the points to note here-

  1. In the component, loader function named loader is written.
  2. Uses fetch API to get data from the given URL. Only 10 posts are fetched.
  3. If there is no error in fetching data (response is ok) then you can return data directly with React Router V7.
  4. Data fetched by the loader function is retrieved by using the useLoaderData() hook.
  5. Post data is then iterated to print id and title of each post. With each post a Link with its id is also created

src\components\routes\PostDetails.js

import { useLoaderData } from "react-router";

const PostDetails = () => {
  const postData = useLoaderData();
  return(
    <>
      <h2 className="text-center">{postData.title}</h2>
      <div>{postData.body}</div>
    </>
  )
}

export default PostDetails;

export async function loader({request, params}){
  const url = "https://jsonplaceholder.typicode.com/posts/"+params.postId
  const response = await fetch(url);
  if (!response.ok) {
    throw new Response('Error while fetching post data', {status:404});
  }
  else{
    const responseData = await response.json();
    return responseData;
  }
}

Some of the points to note here-

  1. In the component, loader function named loader is written which is used to fetch data by post Id.
  2. In loader function you can’t use useParams() hook to get the route parameters. Router passes an object to the loader function that has two properties- request and params.
  3. Using request you can access the request body, request URL etc. Using params you can access the route path parameters.
  4. Data fetched by the loader function is retrieved by using the useLoaderData() hook. In this case data is post data for a particular ID.
  5. Post title and post body are rendered by this component.

PostList Page

Data Loader With Dynamic Routes

Post Detail page

Loader in React Router

That's all for this topic Data Loader With Dynamic Routes in React. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Routing in React With Example
  2. Setting 404 Error Page With React Router
  3. useNavigate in React Router to Navigate Programmatically
  4. useSearchParams in React Router - Handling Query Parameters
  5. Search Filter Using useSearchParams in React Router

You may also like-

  1. React Declarative Approach
  2. React Virtual DOM
  3. Controlled and Uncontrolled Components in React
  4. JavaScript Array map() Method With Examples
  5. ArrayList in Java With Examples
  6. Count Number of Times Each Character Appears in a String Java Program
  7. Java Stream API Interview Questions And Answers
  8. What is Client Side Routing in Angular

No comments:

Post a Comment