T
TanStackโ€ข3y ago
vicious-gold

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
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-gold
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
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-gold
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
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-gold
vicious-goldOPโ€ข3y ago
whenever I use one of the two buttons regardless of if I used the filter before or not
harsh-harlequin
harsh-harlequinโ€ข3y ago
You can achieve this by not using keepPreviousData. Is this what you want?
vicious-gold
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 blurred
harsh-harlequin
harsh-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-gold
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
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-gold
vicious-goldOPโ€ข3y ago
Thanks a bunch ๐Ÿ™‚ Enjoy food
harsh-harlequin
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-gold
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
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:
placeholderData: (previousData) => ...whateveryouwant...
placeholderData: (previousData) => ...whateveryouwant...
you can decide, based on previousData, if you want to keep it or not
vicious-gold
vicious-goldOPโ€ข3y ago
Uhhh nice ๐Ÿ™‚ Thanks for the response and the look-ahead
fascinating-indigo
fascinating-indigoโ€ข3y ago
Can you try it out with v5 alpha ? It's already available
vicious-gold
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 undefined
fascinating-indigo
fascinating-indigoโ€ข3y ago
would passing previousQueryKey into the function be helpful ? like: placeholderData: (previousData, previousQueryKey) => ... ?
vicious-gold
vicious-goldOPโ€ข3y ago
That was my first intuition to receive some kind of info about the previous queryKey yeah
fascinating-indigo
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-gold
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
fascinating-indigoโ€ข3y ago
thanks for trying out v5 btw โค๏ธ you're the second person to ask about "previous query key", so ... ๐Ÿ˜…
vicious-gold
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 way
xenial-black
xenial-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 ['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
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 entry
xenial-black
xenial-blackโ€ข3y ago
Yeah we currently dont keep track of that ๐Ÿ˜… but we could!
fascinating-indigo
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-gold
vicious-goldOPโ€ข3y ago
๐Ÿ™‚ Has anything changed about the dev tools? Can't get those to work again in the code sandbox. ๐Ÿค”
queryClient.getQueryCache is not a function
at ReactQueryDevtoolsPanel2 (
queryClient.getQueryCache is not a function
at ReactQueryDevtoolsPanel2 (
fascinating-indigo
fascinating-indigoโ€ข3y ago
can you share the sandbox?
xenial-black
xenial-blackโ€ข3y ago
Yeah I saw that error too!
xenial-black
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
fascinating-indigoโ€ข3y ago
I'll add tests in a bit
๐Ÿคฃ related to my tweet ๐Ÿ™ˆ ?
xenial-black
xenial-blackโ€ข3y ago
Hahahahaha I didn't see that tweet until now ๐Ÿคฃ
fascinating-indigo
fascinating-indigoโ€ข3y ago
change looks good. let's hope this works with select ๐Ÿ˜…
vicious-gold
vicious-goldOPโ€ข3y ago
Haha that tweet timing ๐Ÿ’ช
fascinating-indigo
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-uhz7zq
vicious-gold
vicious-goldOPโ€ข3y ago
Can I do "stupid stuff" now that the whole query is exposed inside the previousDataFn?
fascinating-indigo
fascinating-indigoโ€ข3y ago
you can try it out with the codesandbox preview build:
"@tanstack/react-query": "https://pkg.csb.dev/TanStack/query/commit/482dd161/@tanstack/react-query",
"@tanstack/react-query-devtools": "https://pkg.csb.dev/TanStack/query/commit/482dd161/@tanstack/react-query-devtools",
"@tanstack/react-query": "https://pkg.csb.dev/TanStack/query/commit/482dd161/@tanstack/react-query",
"@tanstack/react-query-devtools": "https://pkg.csb.dev/TanStack/query/commit/482dd161/@tanstack/react-query-devtools",
vicious-gold
vicious-goldOPโ€ข3y ago
like a refetch or smth
fascinating-indigo
fascinating-indigoโ€ข3y ago
I wouldn't do side-effects in there ... it runs during render
vicious-gold
vicious-goldOPโ€ข3y ago
Yeah I wouldn't either. But could you?
fascinating-indigo
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 then
xenial-black
xenial-blackโ€ข3y ago
Not sure if it's just my machine but I can still see this error on the csb link you posted
No description
fascinating-indigo
fascinating-indigoโ€ข3y ago
I have no error here @Aryan : https://uhz7zq-5174.csb.app/
vicious-gold
vicious-goldOPโ€ข3y ago
Mine is gone as well How do I do this? Update package.json and run yarn? Doesn't do it
xenial-black
xenial-blackโ€ข3y ago
quickest-silver
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!

Did you find this page helpful?