Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reasons for using (isLoading or isFetching) in react-query

I am a user who uses react. I didn't use the isloading function well while using react-query. In terms of ui, I thought that is loading was used to show the loading screen to the user. I thought I didn't have to show loading because the data fetch is fast.

But suddenly, this thought occurred to me.

If you hand over props to a child component, after the data passes 'undefined' and gets fetching, you often render the fetch data, so I thought it might be because of the reason for optimizing rendering, or is there another reason?

like image 475
pvp11 Avatar asked Sep 02 '25 04:09

pvp11


1 Answers

I think your question deserves a slightly more detailed answer because isFetching is very often ignored.

isLoading

As you’ve discovered, a query might load quickly enough that checking for isLoading may seem unnecessary.

Many examples use this pattern:

  const { data, isLoading } = useQuery(...);

  if (isLoading)
    return <div>Loading...</div>;

  return <DataTable data={data} />;

While the data is being fetched the first time (UseQueryResult.status === "loading") you display a loading indicator and when the data is available you can use it as you please.

Delayed loading indicator

If the query is fast to load then you'll briefly see "Loading..." (or a spinner) and that's not a good UI. For very short delays, it's better to display nothing at all: you can do it with an animation (or setting a timer to make the spinner visible), it does not really matter as long as you embed this in your <LoadingIndicator /> component. I found that a 100/150 ms delay is a good compromise (for me). Out there there are studies to determine what the most appropriate value is, if you're interested.

Errors

You also want to handle errors, there is isError for that (alternatively you can simply use status for everything). A slightly more complicate implementation will look like this:

const { status, data, error, refresh } = useQuery(...);

if (status === "loading")
  return <LoadingIndicator />;

if (status === "error")
  return <Error error={error} onRetry={refresh} />

return <DataTable data={data} onRefresh={refresh} />;

Note how we introduced refresh(), when we call it we will cause isFetching to be true (which does not happen for the initial fetch).

isFetching

As we saw, isFetching is true when we already have a value (or attempted a first fetch) and we're fetching the same data again. This is true when we manually trigger a refresh but also when react-query is re-loading cached data (in this case status === "success").

This is very important in few cases:

  • We might not want to show a loading indicator when refreshing the table.
  • When isRefresh is true and data !== undefined we may want to simply disable editing (where supported) without showing any loading indicator (or using a different subtler one).

We might also want to display stale data using a subtle visual clue (for example dimming the text), if nothing changed then we'll have minimum flickering and layout changes when fresh data is available. See also isPreviousData.

Reuse

As you can see you will probably have a lot of boilerplate code around a simple query. What I like to do is to build one reusable component:

const query = useQuery(...);

return (
  <Query query={query}>
    ({ data }) => <DataTable data={data} />
  </Query>
);

Accessibility

Do not forget to include aria-live and aria-busy attributes, the outer container (parent for the data and the loading/error indicators) could be, for example, be defined like this:

<section aria-live="polite" aria-busy={isLoading || isFetching}>

Exact implementation depends on your specifics but do not forget to include ARIA attributes also for the loading indicator (especially if using animations/icons):

<div role="alert" aria-live="polite" aria-label="Loading" />

and for the error banner you may include role="alert" (in this case the default aria-live="assertive" implied by the "alert" role is appropriate).

like image 115
Adriano Repetti Avatar answered Sep 05 '25 01:09

Adriano Repetti