skip to Main Content

I am using React with React-Router-Dom. For some pages, I am using the loader as part of the route so I have the data when the page is loaded. The problem is that this data may take awhile to load from the api, and until it is loaded, the user gets no confirmation that their click did anything. Here are some situations when this happens:

  1. When navigating to the next page where data needs to be loaded, the user clicks a button that is supposed to take them to that page. Instead of instantly taking them to the page, nothing changes, but the requests are made, then the page loads once that data is ready. This means that after the user clicks the button to take them to the page, they are stuck looking at the current page until it is fully loaded.
  2. When navigating using a URL, lets say to /dashboard. The user is taken to the page, but the page is completely blank until the page is fully loaded. The user is stuck looking at a white page for about 500ms to 1sec (depending on API speed and their internet speeds).

Both of these situations are not ideal and would like a solution. Here is what the code looks like:

//index.ts
import ReactDOM from "react-dom/client";
import {
    createBrowserRouter,
    RouterProvider,
} from "react-router-dom";

const router = createBrowserRouter([
    {
        path: "/dashboard",
        element: <Dashboard />,
        loader: async () => {
            const data = await getData()
            return data
        }
    }
])

ReactDOM.createRoot(document.getElementByID("root")).render(
    <RouterProvider router={router} />
)
//dashboard.tsx
import { useLoaderData } from 'react-router-dom';
export default function Dashboard() {
    const data = useLoaderData();
    console.log(data);
    return (
        <p>{data.name}</p>
    )
}

How do I navigate instantly and show a loader until the data from useLoaderData is available?

I have already tried going into the index.html and adding a loader inside the <div id="root>
but this didn’t work due to the page being overwritten with a white screen while the data was loading. I also tried putting a loader outside the div and removing it on page load using useEffect, but having to do this on every single page is troublesome.

I also tried deferring the data like in the react router guide but it didn’t work for me as the getData functions await the fetch in an async function from my api. Here is what getData looks like:

export async function getData() {
    const response = await fetch(`${backendURL}/getData`)
    const data = await response.json()
    return data;

I know the problem is that page loading is being blocked by the async await, but I have no idea how to fix it.

2

Answers


  1. I usually use this package:

    https://www.npmjs.com/package/react-loading-screen

    I don’t really know how good practice it is but while I’m fetching stuff from an endpoint or the database, I just call the react-loading screen while not a timeout and it makes wonders.

    Hope this help!

    Login or Signup to reply.
  2. This might be what you’re looking for: https://beta.reactrouter.com/en/dev/guides/deferred

    Another solution would be at the Root level:

    <Suspense> relies on a promise being thrown, which the <Outlet> doesn’t do while the route’s loader is still running.
    Instead, you can use useNavigation to access the current navigation state and show a loading component:

       export default function Root() {
          const notes = useLoaderData();
          const { state } = useNavigation();
        
          return (
            <>
              {state === 'loading' && (
                <progress
                  style={{
                    position: 'absolute',
                    top: '0',
                    left: '0',
                    width: '100vw',
                  }}
                />
              )}
              <div style={{ display: 'flex' }}>
                {/* same code as before */}
              </div>
            </>
          );
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search