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

useQuery runs twice on initial load with React 18 #3633

Closed
facu-01 opened this issue May 20, 2022 · 4 comments
Closed

useQuery runs twice on initial load with React 18 #3633

facu-01 opened this issue May 20, 2022 · 4 comments

Comments

@facu-01
Copy link

facu-01 commented May 20, 2022

Describe the bug

Using axios, if you pass the signal parameter, the api call runs twice (cancelling the first) on page reload.
I think that is the same bug that: ##3492

Your minimal, reproducible example

https://codesandbox.io/s/funny-sid-odqlqr?file=/src/App.js

Steps to reproduce

Open the network tab, refresh the Browser output and see two API calls(one cancelled).

Expected behavior

Only one api call.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

...

react-query version

v4.0.0-beta.1

TypeScript version

No response

Additional context

No response

@TkDodo
Copy link
Collaborator

TkDodo commented May 21, 2022

This is the expected behaviour, or at least, there is not a lot we can do about it. This is related to strict effects in react 18, which means you'll only see this behaviour if you use <StrictMode>, and only during development. In that mode, react quickly mounts and unmounts every component to stress-test the app and to simulate quick user interaction. So what happens is:

  • component mounts, fetches
  • component unmounts. Since you only had one observer and you consumed the AbortSignal, the fetch is cancelled.
  • component mounts again, another fetch.

If you don't consume the AbortSignal, the second fetch will not fire because the first one is still ongoing. You can read more about this here: facebook/react#24502 (comment)

This is different from #3492, because with InfiniteQueries, we currently always abort fetches even if the AbortSignal is not consumed, which is likely a bug (we're still discussing it on the PR).

@fzaninotto
Copy link

fzaninotto commented Jun 5, 2024

Thanks for the response. We've discovered this unexpected behavior in react-admin after adding support for query cancellation.

We were really surprised that the queries are doubled even if we don't pass down the signal to the actual API client. Destructuring the queryFn parameters is enough to trigger the doubling - probably due to the fact that the signal is implemented via a a getter in the params.

// this is enough to trigger the doubling
const result = useQuery<RecordType>({
    queryKey: [...],
    queryFn: ({ signal }) => { ... }
});

// this does not trigger the doubling
const result = useQuery<RecordType>({
    queryKey: [...],
    queryFn: () => { ... }
});

Is there a way to make the signal handling opt-in, i.e. to enable query abortion only if the underlying API client supports it?

@TkDodo
Copy link
Collaborator

TkDodo commented Jun 5, 2024

The opt-in way is destructing / using the signal. If the underlying fetch client doesn't support it, don't destruct it.

if you destruct the signal from the passed in object, it's seen as "used" because we use custom getters on that property. That means the query gets cancelled, state thrown away, and you'll see a fresh second fetch. But it shouldn't be aborted in the network tab.

you can do:

const result = useQuery<RecordType>({
    queryKey: [...],
    queryFn: (context) => fetch(..., { signal: supportsAbort ? context.signal : undefined }
});

that way, you don't invoke the getter unless you support abort.

@fzaninotto
Copy link

Thanks, that's what we ended up doing.

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

3 participants