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

RTK Query: Lazy query returns deprecated data while fetching the same data via tag invalidation #2802

Open
C3ntraX opened this issue Oct 20, 2022 · 14 comments
Labels
bug Something isn't working rtk-query
Milestone

Comments

@C3ntraX
Copy link

C3ntraX commented Oct 20, 2022

Describe the bug
I found a bug regarding the combination of declarative and imperativ querying at the same time (Multiple subscribtions).
If you execute a lazy query after an invalidation of the same data through which fetches the same data via data query, then the lazy query will not execute a request if "preferCached" is false.

This means that Lazyquery will ignore an ongoing fetch of the same data and returns deprecated data.

See the example, its hard to explain.

Isolated Example
https://stackblitz.com/edit/react-ts-tkvbea?file=index.tsx,reduxRtk.tsx,customQuery.ts,App.tsx,package.json

To Reproduce
Steps to reproduce the behavior:

  1. Go to the Sandbox and open App.tsx
  2. Open Console
  3. Click on Add button
  4. See: QueryData will get the new data; LazyQueryData hold the cached deprecated data and will ignore the running request. And this causes the LazyQuery to be logging the data before the query will finish.

What happens

  1. You click the "Add" button.
  2. This executes useAddDataMutation
  3. The Mutation invalidates all tags with type "Test"
  4. useGetDataQuery will request new data, because the tag got invalidated
  5. Imerative after step 2, the useLazyGetDataQuery will try to get the new data too.
  6. useLazyGetDataQuery won´t wait for the current query executed with useGetDataQuery and returns deprecated data; This happens if preferCachedData is false.

Expected behavior
The lazy query should joining the ongoing request and wait for the request.

Additional context
I need both ways to request data declaratively and imperatively. With the imerative way I do the printing of the data. So it's very important that it works somehow. I know to work around this, but to add an additional API that doesn't invalidate the "test" tag. This will prevent the problem, but yes.

@C3ntraX
Copy link
Author

C3ntraX commented Oct 25, 2022

Hallo @markerikson and @phryneas,

any comments about this topic?
I don´t think, this is intended, that lazy querys do not fetch if preferCached is false or undefined
Thanks

BR

@phryneas
Copy link
Member

A lazy query is essentially just another way of subscribing to a cache value and starting a request on top if desired.

Since with RTK Query you will only have one cache entry for a certain argument, it will latch on to existing cache entries - and usually that is an intended behaviour.

If you don't want that behaviour, you could add something random to your query arg so it gets it's own cache entry - so

trigger({ foo: "bar" })

would become

trigger({ foo: "bar", __: uuid() })

Generally though, the point of queries is pretty much sharing cache values. If you don't want to share cache values between components, going with a mutation might even be a better choice.

@C3ntraX
Copy link
Author

C3ntraX commented Oct 29, 2022

Hello @phryneas,

I know how this works. But the problem is what I described. The lazy query does not request and and/or wait for an ongoing fetch with .unwrap() if I don´t want to use the cached data for the subscribtion.
I think this is a bug. Because preferCached = false should request the latest data, but this is not the case. Again, pls see my example.

@phryneas
Copy link
Member

Yeah, but the primitive to that is not useLazyQuery.
The point of useLazyQuery is still to latch onto an existing cache entry. That's the whole thing it does.
And sometimes it will also trigger a refetch.

You interpret a feature in here that never was a design goal, or documented - so that's definitely not a bug, but of course unfortunate for what you want to do.

If you really want to force starting with an empty cache entry, I already explained above how you can force that empty cache entry.

@Valen-Pony
Copy link

@phryneas From the doc it says

When the trigger function returned from a LazyQuery is called, it always initiates a new request to the server even if there is cached data

So when the trigger is called, we should expect it will do a refetch and return with the latest data right?

And now the trigger.unwrap() behavior is

  1. do a refetch
  2. return the cached data
  3. if remove the providesTags, the behavior become: trigger always return the latest data

I belieave it is not expected. Please check this example: https://codesandbox.io/s/bitter-rain-qigmkt?file=/src/features/posts/PostsManager.tsx. Or see the gif if you want :)

bug

@C3ntraX
Copy link
Author

C3ntraX commented Nov 1, 2022

Yes, the docs don't tell you that the query won't fetch the data again if there's already a pending query triggered via tag invalidation.

Its the same problem I already described.

@fjpedrosa
Copy link

fjpedrosa commented Nov 3, 2022

@C3ntraX I have the same problem, seems that trigger() is not executing the refetch because the mutation already did, so the response of trigger() contains status: 'pending' and old data cached.

Using .unwrap() the returned object from trigger() is being modified so only the data property is returned.

I'm not sure if this is a bug or the expected behaviour. If second, how to "manually" execute an api call with no need to be subscribed?

@phryneas
Copy link
Member

phryneas commented Nov 3, 2022

Generally: if a query call for a cache entry is already running, RTK Query will never start a new one. Any new query inititated will latch onto the existing query.

If you want to start a new one, you would have to use api.util.getRunningQueriesThunk (see the current 1.9 RC) to get a handle for the running operation, .abort() that and then initiate a new call.

@C3ntraX
Copy link
Author

C3ntraX commented Nov 5, 2022

"Generally: if a query call for a cache entry is already running, RTK Query will never start a new one. Any new query inititated will latch onto the existing query."

If you unwrap the lazy query and wait for the uncached data (preferCached = false), thats not the case. No latch onto the existing query happens. If you ask me, this is a bug, because I expect it and its not documented, not to do so (See the comments and codeexamples).

@markerikson
Copy link
Collaborator

We'll try to look into this at some point, but realistically both Lenz and I are not going to be actively working on RTK stuff for the next few weeks.

@mohitsati14
Copy link

@markerikson @phryneas Any plans for fixing this bug?

@SamuelGDMG
Copy link

Hi @C3ntraX, I've had the same problem as you describe, what I did to fix this problem was to remove the invalidation of my mutation and move it for a dispatch(api.util.invalidateTags([{ type: foo, id: bar }])), but for my lazyQuery every request was different parameters, so I could not get the data that was on the cache. I ran the dispatch after the API get the data, since I don't need the old data, remember that RTK uses the parameters of the function as a queryCacheKey. In the example that you show, actually, you don't need to reset the cache by the mutation, since every time you call the API again, the data in your cache will be always rewritten.

@rwilliams3088
Copy link

I ran into this issue today whilst attempting to move over to RTK Query from GraphQL. For the moment, I'm just going to avoid using tags as caching is not essential for my application. However, it is less than ideal to not be able to make use of caching. This behavior is highly unintuitive and I would definitely consider it a bug. I would very much like to see this addressed. +1

@noanflaherty
Copy link

I had been battling a bug for a number of hours before stumbling upon this thread. I agree that the behavior is very unexpected. I would expected that if I pass preferCached = false, the unwrapped trigger should never return a cached value. I would be a big proponent of fixing this issue, or at a minimum, updating the documentation to make this behavior clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working rtk-query
Projects
None yet
Development

No branches or pull requests

9 participants