英文:
How to normalize react-query cache to only use a single key when there are multiple keys?
问题
My useQuery
调用了一个 API (/posts/:idOrSlug
),其中每个资源可以通过两个键中的任一个来标识 - 一个是 ID,另一个是 slug。最初,前端只有 slug 而没有 ID,但 useQuery()
网络调用会返回 ID。
我要如何使得 react-query 缓存:1. 只存储每个项一次(而不是为 slug 和 ID 分别存储),2. 最好将 ID 作为主键(因为 ID 是不可变的,而 slug 理论上可能会改变)?
基本上,我想要从 useQuery()
中的键从 slug 变为 ID。最初我打算通过将 onSuccess
添加到 useQuery()
中手动更新缓存,但是这个回调被弃用了(而且我想肯定有更清晰的方法)。
对于我特定的用例,我可以详细说明一下 - 想象一个博客应用程序,前端最初只有来自 URL 的文章 slug,而没有文章 ID,但调用 GET /posts/:idOrSlug
会返回文章 ID。当调用 useQuery
时,我最初不知道 ID 是什么,所以不太确定该如何设置 queryKey
。
编辑:所以现在我正在手动设置 useQuery()
的 queryFn
中的 react-query 缓存,使用 queryClient.setQueryData(["posts", { id: postData.id }], data);
。然后我只是创建了一个将 slug 映射到 ID 的本地映射,如果我知道 slug 的 ID,我会在 queryKey
中使用 ID。这样做可以运行,但缺点是缓存数据会重复存储,因为它同时存储了 slug 和 ID。此外,我认为这相当丑陋,因为缓存在这里是命令式地更新的,而更声明性的方法会更清晰 - 但是 react-query 似乎并未在文档中说明如何以声明性的方式设置缓存 ID(至少我在文档中找不到)。
英文:
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).
答案1
得分: 1
这是正确的方法。唯一需要不同的是(因为他们取消了useQuery的onSuccess),要在你的查询缓存中直接指定onSuccess。
当缓存的onSuccess获取到id查询的新数据时,它可以为slug查询填充缓存,反之亦然。
这个方法可以工作,但再次的缺点是缓存数据会重复存储,因为它通过slug和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).
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.
答案2
得分: 0
另一种方法可以是将 useQuery 钩子包装在另一个钩子中,该钩子在内部解析为相同的键吗?
英文:
Could another approach to this be to wrap the useQuery hook in another hook which internally resolves to the same key?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论