reset query with `keepPreviousData` to `isLoading` when query-key changes
Hey there,
maybe I'm totally handling this wrong but I tinkered with this problem quite a bit now and can't get to the solution. Maybe it's even a bug?!
I created this sandbox to illustrate my problem https://codesandbox.io/p/sandbox/reactquery-with-keeppreviousdata-6eg4bp?file=%2Fsrc%2Findex.jsx
In my app I want to switch a parent entity who's ID is part of the query-key as the results of a fetch-request are based upon this ID (displaying siblings of that entity). Also the siblings can be filtered by using a filter string.
Before filtering when changing the entities the loading state is correctly shown (IMO). But once I filtered the loading state is never shown again - despite of having or not having a filter when switching entities.
Hope this all makes sense and someone can enlighten me. ๐
Thanks
reactQuery with keepPreviousData
CodeSandbox is an online editor tailored for web applications.
49 Replies
harsh-harlequinโข3y ago
Hi ๐
To attempt to answer the questions from the reproduction:
- Why is the list returning to it's unfiltered state although
keepPreviousData is set?
I imagine this is down to both you imperatively resetting the query and/or changing the query key. If it's a new query key, it's a new cache entry and there's nothing to keep.
- Why is the "correct" isLoading never returned anymore after I filtered once?
- Is there a way to always get into isLoading state again when changing entities?
The loading state looks fine to me. The list is disabled when filtering or changing query keys, regardless of whether or not it's been filtered before. Am I missing something here?vicious-goldOPโข3y ago
When you never filtered before and use the buttons to switch entities you always get a "Loading..." output. But if you filtered before it doesn't behave like this anymore.
I want to always display "Loading..." when switching entities and disable the list when using the text filter.
So the behaviour is correct from the acceptance criteria part before using the filter but broken afterwards
harsh-harlequinโข3y ago
Oh, sure. That's because you're using keepPreviousData and it's returning the cached data without putting the query into a loading state
vicious-goldOPโข3y ago
Can I force the latter?
Since I want to keep previous data when using the text filtering to display the old data until the filtered result is returned
harsh-harlequinโข3y ago
Putting the query state into a loading state when it's retrieving fresh cached data? No
You can derive whatever you want from the information returned from the query hook though
When do you want to display the loading message?
vicious-goldOPโข3y ago
whenever I use one of the two buttons regardless of if I used the filter before or not
harsh-harlequinโข3y ago
You can achieve this by not using keepPreviousData. Is this what you want?
vicious-goldOPโข3y ago
When filtering I want to still show the list in a disabled state. That's why I set
keepPreviousData - or can this be done differntly?
It's pretty much like
- on button press always show "Loading..." (while also reseting filters)
- on filtering show previous result but blurredharsh-harlequinโข3y ago
I think you can use isFetching instead of isLoading here to determine when you want to display the loading message. As you reset the query on button press, it'll fetch
vicious-goldOPโข3y ago
But it's also fetching on filter-changes - where I want to only blur
How would I distinguish between those states?
separate state to keep track of if I'm swapping entities?
harsh-harlequinโข3y ago
Usually you'd use a combination of isLoading/isFetching and !isPreviousData, but that won't work either here I don't think
You should be able to derive this from the hook return values but it's an interesting set of requirements
I'll see if I can take a proper look after lunch
vicious-goldOPโข3y ago
Thanks a bunch ๐ Enjoy food
harsh-harlequinโข3y ago
I had a little play with this and I can't seem to satisfy all of your requirements by deriving booleans from the query hook return value. I'm really hesitant to suggest to suggest additional state, but I can't actually see how you'd satisfy the keeping previous data requirement and only showing the loading message when a specific member of the query key changes without it. Sorry I couldn't be of more help!
vicious-goldOPโข3y ago
No worries. You were a lot of help already. I was going nuts that I couldn't find a valid combination of returned booleans either. But thanks for verifying.
Also don't feel like keeping state of what I'm doing currently as it will most likely get out of sync at some point
Trying to find a different UI solution therefor. Either always blur or always loading - will need to discuss with UX and PO ๐
fascinating-indigoโข3y ago
I think this will be possible with v5. We're merging
keepPreviousData with placeholderData, so you'll get full control with the placeholderData-function:
you can decide, based on previousData, if you want to keep it or notvicious-goldOPโข3y ago
Uhhh nice ๐ Thanks for the response and the look-ahead
fascinating-indigoโข3y ago
Can you try it out with v5 alpha ? It's already available
vicious-goldOPโข3y ago
I updated the codesandbox to use the v5 alpha. And I see I can now determine whether I want or do not want to return previousData - which helps coering the AC of always showing the loading... state when changing entities. Nice thank you!
How would you approach keeping old data though when using text filter? Do you get access to the previous queryKey or something? Or will I need to keep track of the previous entity's fakeId and check against that? Like barebone React useState/useRef?
Like I want to check if the
fakeId (or other parts of the query-key if spoken in a more general way) changed and only then return undefinedfascinating-indigoโข3y ago
would passing
previousQueryKey into the function be helpful ?
like: placeholderData: (previousData, previousQueryKey) => ... ?vicious-goldOPโข3y ago
That was my first intuition to receive some kind of info about the previous queryKey yeah
fascinating-indigoโข3y ago
or maybe even:
placeholderData: (previousData, previousQuery) => ...
gonna talk to @Aryan about it to see if it's possible. Not sure if we currently persist the whole previous query ๐คvicious-goldOPโข3y ago
Sure, don't bother adding it for my singular use case though. If you don't see a more wide spread use for this
fascinating-indigoโข3y ago
thanks for trying out v5 btw โค๏ธ
you're the second person to ask about "previous query key", so ... ๐
vicious-goldOPโข3y ago
No worries ๐
Alright, nice ๐ Seems like there is a use case then
I feel like my particular problem could be solved outside of react-query but I really don't want to keep that in sync
So it would be super nice to receive the
previousKey or previousQuery to be sure in what to return
Let me know when there is another version I can try or help out any other wayxenial-blackโข3y ago
We do keep track of the previousQuery but the issue here would be in this scenario: Say you have loaded the query with initial query key ['people', 'fake-id-1', ''].
Now you type the filter in rapid succession so the query key changes from ['people', 'fake-id-1', ''] -> ['people', 'fake-id-1', 'L'] -> ['people', 'fake-id-1', 'Lu'].
Both
Both
['people', 'fake-id-1', 'L'] and ['people', 'fake-id-1', 'Lu']. will be in loading states but with placeholderData we show the last loaded data from ['people', 'fake-id-1', ''].
So in the placeholderData function callback (placeholderData: (previousData, previousQuery) => ...) should the previousQuery for the currently mounted query (['people', 'fake-id-1', 'Lu'] ) be ['people', 'fake-id-1', ''] or ['people', 'fake-id-1', 'L']?fascinating-indigoโข3y ago
I'd say the query we pass in should be the same as the previousData we pass. So
[people, fake-id-1, '']
basically skipping the in between entryxenial-blackโข3y ago
Yeah we currently dont keep track of that ๐
but we could!
fascinating-indigoโข3y ago
So that previousData is the same as previousQuery.state.data
Seems like we should just track the query instead of data and then grab data from therr
vicious-goldOPโข3y ago
๐
Has anything changed about the dev tools? Can't get those to work again in the code sandbox. ๐ค
fascinating-indigoโข3y ago
can you share the sandbox?
xenial-blackโข3y ago
Yeah I saw that error too!
vicious-goldOPโข3y ago
reactQuery with keepPreviousData
CodeSandbox is an online editor tailored for web applications.
xenial-blackโข3y ago
https://github.com/TanStack/query/pull/5358 Also PR is up. I'll add tests in a bit
GitHub
feat(query-core): Add previousQuery to placeholderFn by ardeora ยท P...
This PR adds another parameter to the placeholderFn called previousQuery to useQuery. This parameter can be used to inspect the query which contained the last defined data for that observer.
Pendin...
fascinating-indigoโข3y ago
I'll add tests in a bit๐คฃ related to my tweet ๐ ?
xenial-blackโข3y ago
Hahahahaha I didn't see that tweet until now ๐คฃ
fascinating-indigoโข3y ago
change looks good. let's hope this works with select ๐
vicious-goldOPโข3y ago
Haha that tweet timing ๐ช
fascinating-indigoโข3y ago
the sandbox works for me after I clone it and restart
npm run dev
https://codesandbox.io/p/sandbox/reactquery-with-keeppreviousdata-forked-uhz7zqvicious-goldOPโข3y ago
Can I do "stupid stuff" now that the whole query is exposed inside the
previousDataFn?fascinating-indigoโข3y ago
you can try it out with the codesandbox preview build:
vicious-goldOPโข3y ago
like a refetch or smth
fascinating-indigoโข3y ago
I wouldn't do side-effects in there ... it runs during render
vicious-goldOPโข3y ago
Yeah I wouldn't either. But could you?
fascinating-indigoโข3y ago
well can you call
fetch() inside your render function? You sure can, nothing stops you. But it absolutely breaks the rules and it's not guaranteed that things will work thenxenial-blackโข3y ago
Not sure if it's just my machine but I can still see this error on the csb link you posted

fascinating-indigoโข3y ago
I have no error here @Aryan : https://uhz7zq-5174.csb.app/
vicious-goldOPโข3y ago
Mine is gone as well
How do I do this? Update
package.json and run yarn?
Doesn't do itxenial-blackโข3y ago
reactQuery with keepPreviousData (forked)
CodeSandbox is an online editor tailored for web applications.
quickest-silverโข3y ago
Just to add on here - I think I'm facing a similar issue that might be resolved by v5.
I have a query that we want to leverage
keepPreviousData unless a value in the url changes (going from a dashboard with id A to id B). Trying to figure out how to toggle keepPreviousData - when we go to dashboard B, we see the data for dashboard A while B is loading.
I have tried adding a stateful variable to keepPreviousData as well as adding the dashboard id to the queryKey.
Anything else I can do other than upgrade to v5? Thanks kindly!