Skip to content

isFetching is always true when there's no internet #2361

Closed

Description

@brunohkbx

Describe the bug
When fetching a query offline and using @react-native-community/netinfo as a custom event listener the prop isFetching is always true and the prop status is success even though the request hasn't started yet.

To Reproduce
Just follow the docs here and set up onlineManager with @react-native-community/netinfo

Then when you query something:

const {
    data,
    isError,
    isFetching,
    isLoading,
    status,
  } = useQuery('todos', MyAPI.getAll, {
    placeholderData: []
  });

isFetching will be always true when there's no internet.

Expected behavior
It should be false since the request hasn't started yet I guess?

Activity

  1. TkDodo commented on Jun 10, 2021

    @TkDodo
    Collaborator

    Can you provide a reproduction please? Maybe try to create a codesandbox with react-native-web. There's also https://snack.expo.io/

  2. TkDodo commented on Jun 26, 2021

    @TkDodo
    Collaborator

    Any updates on the reproduction please?

  3. brunohkbx commented on Jun 28, 2021

    @brunohkbx
    ContributorAuthor

    @TkDodo sorry for taking so long to answer. I got a little busy last week.

    https://snack.expo.io/@bruno.castro/react-query-offline-bug

    How to simulate:

    1. Download the snack
    2. Open it offline with connection local on expo
      Screenshot from 2021-06-28 14-41-26
    3. The prop isFetching will be always true
  4. TkDodo commented on Jun 28, 2021

    @TkDodo
    Collaborator

    Open it offline with connection local on expo

    Sorry, I don't find this setting, where can I set the Connection to Local please?

    What I have tried is setting the network to offline in the chrome devtools, in which case I see true for isFetching, and react-query does 3 retries. After about 20 seconds, all the retries are done unsuccessfully and the query goes to error state.

  5. brunohkbx commented on Jun 28, 2021

    @brunohkbx
    ContributorAuthor

    @TkDodo you need to run it locally.

    1. Run yarn
    2. Then start the project with yarn start
    3. Press d here
      Screenshot from 2021-06-28 16-35-25
    4. It will open this page:
      Screenshot from 2021-06-28 16-36-25
    5. Then you need to change the connection from Lan to Local

    Setting the network to offline in the chrome devtools is not enough to simulate this, since the cellphone still has internet.

    The following code without internet results in:

    const { isFetching, data, failureCount } = useQuery('todos', getTodos, { retry: 5 });
    console.log(isFetching, failureCount)
    
    true 0
    true 1

    It never resolves to error

  6. brunohkbx commented on Jun 30, 2021

    @brunohkbx
    ContributorAuthor

    Hey @TkDodo did it work?

  7. TkDodo commented on Jun 30, 2021

    @TkDodo
    Collaborator

    I’m on vacation now, will take a look when I’m back :)

  8. TkDodo commented on Jul 16, 2021

    @TkDodo
    Collaborator

    Took a look now, but it doesn't start up for me. It hangs in this state forever and doesn't open anything:

    Developer tools running on http://localhost:19002
    Opening developer tools in the browser...
    

    Not sure where I should type d ? I'm using node 14.16.0. Funnily, the moment it ctrl-c the terminal, the browser tab opens. not really sure what's going on, but isn't there an easier way to reproduce it?

  9. brunohkbx commented on Jul 16, 2021

    @brunohkbx
    ContributorAuthor

    @TkDodo d It's just a shortcut, you can open this link http://localhost:19002 directly into your browser. Besides that, make sure to have a USB cable connected to your phone and to allow the dialog Allow USB debugging?

    I'm afraid that's the only way I could find to reproduce it :(

  10. TkDodo commented on Jul 16, 2021

    @TkDodo
    Collaborator

    I did open localhost manually in the browser.

    make sure to have a USB cable connected to your phone and to allow the dialog Allow USB debugging?

    what phone? The instructions didn't mention anything about any phone ... sorry, I'm not playing dumb here but I'd appreciate a really ELI5 step-by-step guide on what to do to get this running. I was thinking this is some sort of emulation that runs in the browser and doesn't require a real phone? I have an iPhone12 fyi

  11. brunohkbx commented on Jul 16, 2021

    @brunohkbx
    ContributorAuthor

    @TkDodo sorry for not being clear enough. Let me try to find a better way to reproduce it

  12. TkDodo commented on Aug 5, 2021

    @TkDodo
    Collaborator

    I think I found a simple reproduction in web:

    https://codesandbox.io/s/react-query-always-loading-j85h3?file=/src/App.tsx

    steps to reproduce:

    • open the sandbox in a new tab
    • open the browser devtools, turn of your network by emulating offline
    • go back to the browser and click the button once

    --> now a query mounts, and it will stay in loading state forever because we have no internet.

    tbh, I'm unsure in what state the query should be. If the query has already loaded once, it will just stay in the state it is in because we are offline, and will continue to fetch if we get online again (refetchOnReconnect).

    So by following this through, the query should stay in idle state without data and also with isFetching: false. Does that sound right?

  13. TkDodo commented on Aug 5, 2021

    @TkDodo
    Collaborator

    would also ❤️ to hear @tannerlinsley's input on what should generally happen if we try to fetch while being offline, because it might have larger implications, for example:

    • you are offline and manually invalidateQueries, e.g. with a button click

    currently, the fetch also starts even though you are offline, and you will be in isFetching until you get back online. This is pretty much the same scenario as with query mounting.

    one option would be to say: we never fetch anything when we are offline, because refetchOnReconnect will likely trigger a fetch anyhow when we come back online...

  14. tannerlinsley commented on Aug 5, 2021

    @tannerlinsley
    Member
  15. TkDodo commented on Aug 5, 2021

    @TkDodo
    Collaborator

    I think that’s a safe bet, unless people have fetchers that work offline?

    good point. what if you are "fetching" from async storage, or just do Promise.resolve(...). Another argument is that if the backend delivers a cache header (Cache-Control: max-age=60), data will come from the browser cache and it will even work offline (I tested this with the example that goes against the github api), which my proposed change would make impossible. I don't think we can just change that.

    The current behaviour is that we start fetching, and then the retrier pauses because we are offline, that's why you're "stuck" in fetching state. There are only three places were we check if we are online:

    • the retries (mentioned above)
    • when setting up the focus manager, so refetchOnWindowFocus only works if you are also online.
    • when setting up the online manager, so refetchOnReconnect only works when you come back online (this one is kinda obvious)
  16. brunohkbx commented on Aug 5, 2021

    @brunohkbx
    ContributorAuthor

    I think I found a simple reproduction in web:

    https://codesandbox.io/s/react-query-always-loading-j85h3?file=/src/App.tsx

    steps to reproduce:

    • open the sandbox in a new tab
    • open the browser devtools, turn of your network by emulating offline
    • go back to the browser and click the button once

    --> now a query mounts, and it will stay in loading state forever because we have no internet.

    tbh, I'm unsure in what state the query should be. If the query has already loaded once, it will just stay in the state it is in because we are offline, and will continue to fetch if we get online again (refetchOnReconnect).

    So by following this through, the query should stay in idle state without data and also with isFetching: false. Does that sound right?

    Awesome @TkDodo. Thanks! That's exactly the behavior that I described.

    I think that’s a safe bet, unless people have fetchers that work offline?

    good point. what if you are "fetching" from async storage, or just do Promise.resolve(...). Another argument is that if the backend delivers a cache header (Cache-Control: max-age=60), data will come from the browser cache and it will even work offline (I tested this with the example that goes against the github api), which my proposed change would make impossible. I don't think we can just change that.

    The current behaviour is that we start fetching, and then the retrier pauses because we are offline, that's why you're "stuck" in fetching state. There are only three places were we check if we are online:

    • the retries (mentioned above)
    • when setting up the focus manager, so refetchOnWindowFocus only works if you are also online.
    • when setting up the online manager, so refetchOnReconnect only works when you come back online (this one is kinda obvious)

    What if we add a new boolean flag to control this behavior? Something like refetchWhileOffline? Then when this is false, the query would be in idle state

  17. TkDodo commented on Aug 8, 2021

    @TkDodo
    Collaborator

    What if we add a new boolean flag to control this behavior? Something like refetchWhileOffline? Then when this is false, the query would be in idle state

    thought about this, too, but it would probably still involve some breaking changes. With the current behaviour, we also stop refetching when retrying, and refetchOnWindowFocus does also not refetch if you are offline. This wouldn't go well with a flag that defaults to true, so if we do that, I think this flag should control if being online / offline has any impact at all on your query...

  18. scarlac commented on Sep 8, 2021

    @scarlac

    Just want to pitch in and add that this is especially apparent when using React Native and the experimental persistor (AsyncStorage in my case) to create a good caching experience over time.
    The loading & error states get persisted. This means that even though network requests aren't in flight, the state indicates that there are. Speaking from experience, there needs to be custom code around loading and error states so they are never persisted simply because network requests don't persist when reloading an app. The web equivalent is to simply refresh the page.
    Edit: I added my thoughts in this discussion as I realize it's a bit too big for this particular issue: #2649

  19. buglessir commented on Nov 8, 2021

    @buglessir

    I think that’s a safe bet, unless people have fetchers that work offline? Tanner Linsley
    …
    On Aug 5, 2021, 7:21 AM -0600, Dominik Dorfmeister @.***>, wrote: would also ❤️ to hear @tannerlinsley's input on what should generally happen if we try to fetch while being offline, because it might have larger implications, for example: • you are offline and manually invalidateQueries, e.g. with a button click currently, the fetch also starts even though you are offline, and you will be in isFetching until you get back online. This is pretty much the same scenario as with query mounting. one option would be to say: we never fetch anything when we are offline, because refetchOnReconnect will likely trigger a fetch anyhow when we come back online... — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

    Yes, actually people have not offline fetchers 😂
    But at least we should handle the error when client's internet is disconnected...
    I think there should be a feature to cancel or stop retry: number || true

    for example with this config:

    {
          refetchOnReconnect: false,
          retry: 1
    }
    
  20. TkDodo commented on Nov 11, 2021

    @TkDodo
    Collaborator

    we will be tracking this issue and related ones here from now on:

    The plan is to work on this for the next major version, because it will contain breaking changes. Your feedback would be appreciated.

  21. added
    duplicateThis issue or pull request already exists
    on Nov 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already existsv4

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions