1

My useQuery is calling an API (/posts/:idOrSlug where each resource can be identified by either one of two keys - an ID or a slug. Initially the frontend only has the slug but not the ID, but the useQuery() network call returns the ID.

How do I make it so that the react-query cache 1. stores each item only once (instead of duplicating for slug and ID), and 2. preferably uses just the ID as the primary key (since ID is immutable and the slug could theoretically change)?

Essentially I want the key from useQuery() to change from slug to ID. Originally I was going to manually update the cache by adding an onSuccess to useQuery(), but that callback is getting deprecated (and I imagine there must be a cleaner way anyways).

To elaborate more on my specific use case - imagine a blogging application where the frontend initially only has the post slug from the URL but not the post ID, but calling GET /posts/:idOrSlug returns the post ID. I'm not exactly sure what to set the queryKey in the useQuery() to get this desired functionality, again since I initially don't know what the ID is when calling useQuery.


EDIT: So what I'm doing now is manually setting the react-query cache inside the queryFn of the useQuery(), using queryClient.setQueryData(["posts", { id: postData.id }], data);. Then I just created a local mapping of slugs to IDs, and if I know the ID of a slug, I use the ID in the queryKey. This works, but the downside again is that cache data is duplicated since it's stored by slug and by ID. Also I think this is fairly ugly since the cache is imperatively being updated here, when a more declarative approach would be cleaner - but react-query doesn't seem to enable a declarative approach to setting cache IDs (at least it's nowhere in the docs).

2 Answers 2

1

Originally I was going to manually update the cache by adding an onSuccess to useQuery(), but that callback is getting deprecated (and I imagine there must be a cleaner way anyways).

This is the correct way. The only thing you need to do differently (since they deprecated the onSuccess for useQuery) is to specify the onSuccess in your query cache directly.

(See the documentation for details)

When the cache onSuccess gets new data for the id query it can populate the cache for the slug and vice-versa.

This works, but the downside again is that cache data is duplicated since it's stored by slug and by ID.

You don't need to worry about that. You're not duplicating the cache data. You've got 1 copy of the data being referenced by both cache keys. It would only make another copy if you did a clone of the object (or deep copy). Here you're just assigning yet another reference to the same object.

Sign up to request clarification or add additional context in comments.

6 Comments

How do I get the QueryCache from the QueryClient? Don't see any mention of that in the docs
Ok looks like that can be done through queryClient.getQueryCache(). So guessing the strategy here would be to subscribe to that, and then manually update the cache. Would be nice if there's an example somewhere, I can't be the first person to try this
You can also pass the QueryCache you want the queryClient to use when you instantiate it so you can create one configured to your specifications before creating the client.
Edited my answer to include clarification about cache duplication.. You don't need to worry about that.
Your edit mutation should just invalidate the query key for the thing you've changed. Then the query re-loads => onSuccess updates both cache keys, everyone gets the updated data.
|
0

Could another approach to this be to wrap the useQuery hook in another hook which internally resolves to the same key?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.