33

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?

2 Answers 2

31

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).

Sign up to request clarification or add additional context in comments.

3 Comments

One reason to use isFetching rather than isLoading is because of react-query's devs' bizarre decision to make isLoading true when a query is disabled.
I advise you to re-read this answer and re-write some of the paragraphs as they are confusing or written in not the best English..
Also the part for "do not forget to include ARIA attributes" is probably irrelevant for most developers since accessibility is rarely a product requirement in B2B projects
0

I think you hit the nail on the head with some of that.

There is a brief bit of time when your data is undefined which means some of your code might break.

A very simple example

const MyComponent = () => {
  const { data, loading } = useQuery(..)

  if (loading) return <LoadingComponent />

  return (<table> { data.map((item) => <tr>{item.name}</tr>)} </table>)
}

if data is undefined then data.map will break. However you are making a point that you could just check if data exists.

if (!data) return <LoadingComponent/>

But! if your query errored out then data will be undefined and you will be stuck in loading forever when really you should throw an error message.

So you could make use of the error prop to get around that too

  const { data, error } = useQuery(..)

  if !(data || error) return <LoadingComponent />

Now you don't have all that much use for loading, except maybe if you want to let your user know that your data is updating in the background, if you already have cached data.

Eg lets say you've called the query already, and reactquery populates the data using the cache immediately, but its doing a background check to make sure the cached data is up to date, then you can use the loading prop to show a little spinner that your data is syncing!

1 Comment

adding error in the if that returns LoadingComponent will also cause the user to get stuck. You'd better have a second if that returns an error message like if (error) return <ErrorComponent />

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.