如何使用React Query缓存Mongoose populate()生成的多层嵌套数组
优先选择用['watchlist', userId]、['recommendations', userId]这类独立查询键分别存储对应数组,这是更符合React Query设计理念的方案。
你之前的方案存在三个核心问题:
- 代码逻辑本身有误:你写的
oldUser.watchlist === watchlist是全等判断,不是赋值操作,就算修正为赋值逻辑,React Query默认缓存是内存级的,页面刷新后缓存自动清空,自然不会生效。 - 单缓存键存储全量user对象会导致数据冲突:访问推荐页返回的user对象里,watchlist是未填充的id数组,访问收藏页返回的user对象里watchlist是填充后的完整数据,两个接口返回的同key下的user结构不一致,很容易出现缓存覆盖导致的渲染异常。
- 缓存粒度太粗:如果只需要更新收藏列表,你得修改整个user对象的缓存,还会影响用户基础信息、推荐列表等其他和收藏无关的缓存逻辑,失效和更新都很麻烦。
独立存储的优势非常明确:
- 接口和缓存一一对应:请求watchlist的接口本身就是独立的,对应独立的查询键,数据来源和缓存范围完全匹配,不会出现结构不一致的问题。
- 缓存更新更灵活:用户新增/删除收藏时,只需要更新或失效
['watchlist', userId]这一个缓存即可,不会影响其他数据的缓存状态。 - 不需要额外处理数据拼接:不用在onSuccess里手动修改user的嵌套字段,大幅降低出错概率。
如果确实想要保留完整的user对象结构,也可以用带参数的查询键区分不同填充场景:比如给用户接口加查询参数指定要填充的字段,查询键写成['user', userId, { populate: 'watchlist' }],不同填充参数的user数据会分开缓存,避免互相覆盖,但这种方案的维护成本还是比独立存储要高,没有特殊需求不建议用。
修正后的useWatchlist参考写法如下:
function useWatchlist() { const { user } = useAuth() return useQuery({ queryKey: ['watchlist', user.profile_id], queryFn: () => axios.get(`${baseUrl}/${user.profile_id}/watchlist`).then(response => response.data) }) }
用户基础信息可以单独封装一个useUser钩子,查询键用['user', user.profile_id],只存储用户名、头像这类不需要populate的基础字段即可。
内容的提问来源于stack exchange,提问作者Alex Dring
相关产品推荐
相关产品推荐

