Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Beta] Disabled query has isLoading: true property #3584

Closed
maxsbelt opened this issue May 3, 2022 · 41 comments
Closed

[Beta] Disabled query has isLoading: true property #3584

maxsbelt opened this issue May 3, 2022 · 41 comments

Comments

@maxsbelt
Copy link

maxsbelt commented May 3, 2022

Describe the bug

In react-query@beta version has strange behaviour. By default query that has enabled: false option has isLoading: true property (see code sandbox for details). In stable release react-query@^3 is has isLoading: false. I didn't find any notes about this update in change logs so it seems like a bug.

Your minimal, reproducible example

https://codesandbox.io/s/eager-bell-epuvfi?file=/src/App.js

Steps to reproduce

Define simple query with enabled: false option

Expected behavior

Query should have isLoading: false

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

Any

react-query version

4.0.0-beta.7

TypeScript version

Not relevant

Additional context

No response

@TkDodo
Copy link
Collaborator

TkDodo commented May 4, 2022

https://react-query-beta.tanstack.com/guides/migrating-to-react-query-4#the-idle-state-has-been-removed

@TkDodo TkDodo closed this as completed May 4, 2022
@maxsbelt
Copy link
Author

maxsbelt commented May 4, 2022

@TkDodo in such case I think it makes sense to mention in the migration guide that query.isLoading state was updated from false to true for disabled queries, WDYT? I didn't find any note about this change.

@TkDodo
Copy link
Collaborator

TkDodo commented May 4, 2022

The migration guide mentions that the idle state was replaced with isLoading: true and fetchStatus: idle. If your query was in idle state on v3, it will be in loading state on v4. My guess is that's what's happening to you, but not every disabled query will be in loading state, just like not every disabled query was in idle state. If you have data and then disable the query, it will still be in success state.

@olan-go2
Copy link

This is messed up. If the enabled = false, isLoading should be in false as well

@kimFrost
Copy link

This caught me off guard as well.

This page gives a bit of info on the subject
https://tanstack.com/query/v4/docs/guides/queries#fetchstatus

@houssemamiri-logient
Copy link

How to deal with disabled false if we have a loading page that work if isloading is true and the loader is showing

@edemaz
Copy link

edemaz commented Sep 13, 2022

This is really messed up. On big repo that relies heavily on isLoading state, it is a nightmare upgrading to v4.

@atreya2011
Copy link

atreya2011 commented Sep 17, 2022

This totally caught me off guard too! I am leaving a link to this in my repo for my future self 😂 It feels counter-intuitive to leave loading to true when the query is disabled.

@epicmau5time
Copy link

So what to do in this case? If I have a query that is disabled, am I to just use isFetching? There is not really as use for isLoading now that it will always show a spinner on components that do not meet a url param criteria (for my use case).

Is param in url? fetch, if it is not always be enabled = false. Due to this change the spinner is always going even if it does not need to be.

@caweidmann
Copy link

What I ended up doing as quick and dirty workaround is the following:

const enabled = false
const { isLoading: isLoad } = useQuery(['some-key'], someMethod, { enabled })
const isLoading = isLoad && enabled

@epicmau5time
Copy link

I did something slightly different

const useWrapper = ()=> {
    const query = useQuery(['key'], fetchFunction)
    
    return {
        ...query,
        isLoading: query.isLoading && query.fetchStatus !== "idle"
    }
}

@houssemamiri-logient
Copy link

for me it works testing on this
fetchStatus === 'fetching' && status === 'loading'

@changyeamoon
Copy link

this makes sense.

this makes even more sense

What's the reason not to go with this approach? @tannerlinsley @TkDodo

@mattisaa
Copy link

mattisaa commented Sep 27, 2022

It is true that isLoading = query.isLoading && query.fetchStatus === 'fetching' or isLoading = query.isLoading && query.fetchStatus !== 'idle' would solve the problem, but this feels like a very backwards check. It also adds more complexity to the code.

It makes the migration from v3 to v4 a bit worse :/

@TkDodo
Copy link
Collaborator

TkDodo commented Sep 29, 2022

this makes sense.

this makes even more sense

What's the reason not to go with this approach?

because isLoading is strictly a derived boolean from status === 'loading', which also discriminates the type of data on type level. Changing that would be a breaking change.

@epicmau5time
Copy link

this makes sense.
this makes even more sense
What's the reason not to go with this approach?

because isLoading is strictly a derived boolean from status === 'loading', which also discriminates the type of data on type level. Changing that would be a breaking change.

But as it is now. It's a breaking change from v3 to v4. Have so loading spinners on components that shouldn't have them, because the fetch is only to go out when a condition is met. So until it's met, spinners everywhere. I'd consider that a breaking change

@TkDodo
Copy link
Collaborator

TkDodo commented Sep 29, 2022

Yes, it's a breaking change. That's why it was made in a major version (v4). It comes from the idle state being removed, and it's documented in the migration guide.
That's what major versions are for, aren't they...

@epicmau5time
Copy link

epicmau5time commented Sep 29, 2022

So reverting a breaking change. Or mimicking the previous implementation as I did below, is in itself a breaking change? It's reverting to what was present. Now the code needs to be littered with additional contional checks to see if the state is idle or not.

I did something slightly different

const useWrapper = ()=> {
    const query = useQuery(['key'], fetchFunction)
    
    return {
        ...query,
        isLoading: query.isLoading && query.fetchStatus !== "idle"
    }
}

@TkDodo
Copy link
Collaborator

TkDodo commented Sep 29, 2022

It is a breaking change from the perspective of version 4. People that have started with version 4 or that have already changed their code when migrating from v3 to v4 would have to adapter their code. This can only happen in a major v5.

I've already stated what the plans are. For reference:

@epicmau5time
Copy link

epicmau5time commented Sep 29, 2022

Ouch that's unfortunate. So for now wrappers and or additional checks for v4.

@changyeamoon
Copy link

It is a breaking change from the perspective of version 4. People that have started with version 4 or that have already changed their code when migrating from v3 to v4 would have to adapter their code. This can only happen in a major v5.

I've already stated what the plans are. For reference:

Oh this is great! isPending would be a great solution. I don't think anyone would mind if you added this in version 4 🥲 breaking changes in minor upgrades happen all the time 👍

@TkDodo
Copy link
Collaborator

TkDodo commented Sep 29, 2022

Oh this is great! isPending would be a great solution. I don't think anyone would mind if you added this in version 4 🥲 breaking changes in minor upgrades happen all the time 👍

we discussed this and there are good reasons not to do this, sorry. I am working on a PR that adds a new derived flag isInitialLoading that works like isLoading did in v3, as described in the path above. We will get there in v5, but not right now.

@changyeamoon
Copy link

#3584 (comment)

@TkDodo Would you say this is a good pattern with v4? Maybe you were thinking we change the way we use "enabled" or "isLoading"? Maybe I'm still in a v3 mindset and theres a better way to approach it?

@TkDodo
Copy link
Collaborator

TkDodo commented Sep 29, 2022

@changyeamoon yes it's a fine pattern, but you will be able to use the provided flag in the next version:

@mullwaden
Copy link

@TkDodo I might be missing something, new to react-query. But getting strange behavior from isInitialLoading. My codebase is littered with queries relying on isLoading and these all work. But there is one that needs to be disabled and it is causing issues for some of our users some of the time. I suspect it might be due to patchy internet connection.

The code

const SomeComponent = () => {
  const { userIsAdmin } = useAuth(); // never changes (one would need to change account)

  const {
    data,
    isInitialLoading,
    error,
    ...other,
  } = useQuery(['some-key'], someMethod, { enabled: userIsAdmin });

  if (error) {
    return <ErrorDisplay error={error} />;
  }

  if (isInitialLoading) {
    return <Spinner />;
  }

  if (userIsAdmin && data === undefined) {
    throw new Error();
  }

  return <div>success!</div>
}

Sometimes the above will throw. Not often, but it happens a few times per day. "other" in this case is:

{
  "status": "loading",
  "fetchStatus": "paused",  <-- did it get to paused due to connection issues?
  "isLoading": true,
  "isSuccess": false,
  "isError": false,
  "dataUpdatedAt": 0,
  "errorUpdatedAt": 0,
  "failureCount": 0,
  "errorUpdateCount": 0,
  "isFetched": false,
  "isFetchedAfterMount": false,
  "isFetching": false,
  "isRefetching": false,
  "isLoadingError": false,
  "isPaused": true,
  "isPlaceholderData": false,
  "isPreviousData": false,
  "isRefetchError": false,
  "isStale": true
}

@TkDodo
Copy link
Collaborator

TkDodo commented Oct 28, 2022

yes, it gets to paused when there is no internet connection and you run with the default networkMode of online.

isInitialLoading doesn't type-narrow, as you can see, in your example, isLoading is true because that is the state that tells you that you have no data yet.

@mullwaden
Copy link

Thank you Dominic, much appreciated! For myself and others who might misunderstand how to do this properly - what would be the safe way of doing what I am doing in the code example above?

@TkDodo
Copy link
Collaborator

TkDodo commented Oct 29, 2022

  • don't throw Errors during render :)
  • if you want to handle all cases, you have a lot of things to cover. I would just return null or a loading spinner at the end if I fall through all of the cases I care about.

@anarkrypto
Copy link

The solution I found to keep isLoading functional:

const { isInitialLoading, isRefetching } = useQuery(['some-key'], someMethod, { enabled: false })
const isLoading = isInitialLoading || isRefetching;

@FR073N
Copy link

FR073N commented Apr 7, 2023

This behaviour seems to be strange. What is the reason of having isLoading: true when having the query disabled ?

@nerdess
Copy link

nerdess commented May 25, 2023

https://react-query-beta.tanstack.com/guides/migrating-to-react-query-4#the-idle-state-has-been-removed

This link is broken, I assume you mean this piece of doc here:

https://tanstack.com/query/v4/docs/react/guides/migrating-to-react-query-4#the-idle-state-has-been-removed

Very confusing change though, need to plough through my codebase now to handle this.

@SaroGFX
Copy link

SaroGFX commented May 26, 2023

I also wasted much time on trying to figure out why isLoading was true when the query is disabled, does not make sense. I was trying to find the bug in my own code, until i found this post...

@lgj9172
Copy link

lgj9172 commented Jun 2, 2023

Is this intended? Or is there any plan to be revised later? If it's an intuitive api, I think when enabled is false, is loading should also be false.

@IuliiaBondarieva
Copy link

IuliiaBondarieva commented Jun 27, 2023

@lgj9172 unfortunately looks like it's intended, 'cause it's very nonintuitive and strange behaviour. :(
Here are docs:
https://tanstack.com/query/v4/docs/react/guides/disabling-queries

Best solution for this case would be to use isInitialLoading for lazy queries instead:
https://tanstack.com/query/v4/docs/react/guides/disabling-queries#isinitialloading

@TkDodo
Copy link
Collaborator

TkDodo commented Jun 27, 2023

have a look at v5

  • the status has been renamed to pending, so now we have pending, success and error
  • the derived flag is isPending, which is the state you'll be in.
  • isInitialLoading is renamed to just isLoading

so you can keep using isLoading like in v3, but it won't type-narrow and it will fall through if you are offline, because then, no request is being made, so you aren't loading, but you're always pending

@JeremyBernier
Copy link

This is not a design choice, this is incorrect behavior. If a query is not loading, then isLoading should be false. The fact that this even needs to be debated shows that the maintainers are living on another planet.

In the meantime isInitialLoading seems to work, but definitely going to be migrating off of react-query as there's too much of this nonsense.

@tobzy
Copy link

tobzy commented Jul 11, 2023

Agree with @JeremyBernier I'm not very sure how loading should be true when there's no query in progress.

@gregg-cbs
Copy link

lol it makes noooo sense to have isLoading to true when a query is disabled and not loading.
isFetching is good for my use at the moment.

@dileepainivossl
Copy link

dileepainivossl commented Sep 22, 2023

In my case how can I delay the API call, untill visible set to true

  const [visible, setVisible] = useState<boolean>(false);

const {
    isError: voyageStartError,
    isLoading: voyageStartLoading,
    fetchStatus: voyageStartFetchStatus,
  } = useGetQuery<IVoyageLocations, IVoyageGet>(
    ['getStartVoyageLocation', startPoint],
    `voyages/locations/${startPoint}`,
    {
      id: null,
    },
    visible
  );

  const {
    isError: voyageEndError,
    data: voyageEndData,
    isLoading: voyageEndLoading,
  } = useGetQuery<IVoyageLocations, IVoyageGet>(
    ['getEndVoyageLocation', endPoint],
    `voyages/locations/${endPoint}`,
    {
      id: null,
    },
    visible
  );

  if (
    
  ) {
    return <Loading />;
  }

  if (voyageStartError || voyageEndError) {
    return <ErrorOccurred />;
  }

@stouch
Copy link

stouch commented Oct 26, 2023

Not sure why this issue is closed. What are we supposed to do to check if it's just loading once it's enabled ?

@TkDodo
Copy link
Collaborator

TkDodo commented Oct 27, 2023

Not sure why this issue is closed. What are we supposed to do to check if it's just loading once it's enabled ?

isInitialLoading in v4
isLoading in v5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests