RTK Query中updateCachedData无法访问全缓存及updateQueryData不触发问题
RTK Query 无限滚动跨页缓存更新与updateQueryData未触发问题
一、跨页缓存更新场景
组件实现无限滚动功能,通过WebSocket实时更新数据。每页获取10条数据,当前处于第2页时,需要根据WebSocket消息修改第1页中的某条数据,但updateCachedData仅能访问当前第2页的缓存结果,无法修改第1页数据,导致用户切回第1页时看不到更新后的值。
示例代码:
page 1 = [{a: 1}, {b: 1}, {c: 1}]; page 2 = [{e: 1}, {f: 1}, {g: 1}]; when page = 2; updateCachedData(draft => { // draft 仅显示当前页数据 [{e: 1}, {f: 1}, {g: 1}]; // 需要将第1页更新为 [{a: 1}, {b: 5}, {c: 1}] })
二、尝试updateQueryData未触发的问题
查阅文档并参考@markerikson的建议后,尝试使用updateQueryData更新缓存,但该方法未触发,相关代码如下:
async onQueryStarted( arg, { dispatch, // getState, // extra, // requestId, queryFulfilled // getCacheEntry, // updateCachedData } ) { try { await queryFulfilled; dispatch( ApiSlice.util.updateQueryData('getOrderList', arg, (d) => { console.log('draft', d); }) ); } catch (er) { console.log('er', er); } },
解决方案
1. 跨页更新缓存的核心逻辑
RTK Query的缓存按查询参数独立存储,无限滚动的每一页对应不同的查询参数(如{page:1}、{page:2})。要修改非当前页的缓存,需要明确遍历所有已缓存的分页条目,找到目标数据所在的页并更新。
示例实现:
async onQueryStarted(updatedItem, { dispatch, getState }) { // 获取所有getOrderList的缓存键 const cacheKeys = Object.keys(getState().api.queries).filter(key => key.startsWith('getOrderList')); // 遍历每个缓存页,更新目标条目 for (const key of cacheKeys) { const { queryArgs } = getState().api.queries[key]; dispatch( ApiSlice.util.updateQueryData('getOrderList', queryArgs, (draft) => { const targetIndex = draft.findIndex(item => item.id === updatedItem.id); if (targetIndex !== -1) { // 合并更新数据 draft[targetIndex] = { ...draft[targetIndex], ...updatedItem }; } }) ); } }
2. 修复updateQueryData未触发的问题
你的代码存在几个关键问题,对应修正如下:
- 去掉不必要的
await queryFulfilled:如果是WebSocket触发的缓存更新,无需等待mutation完成,直接执行更新逻辑即可 - 确保查询参数匹配:
updateQueryData的第二个参数必须和目标查询的参数完全一致(比如分页查询的{page:1}),如果传入的是mutation的参数(如单个更新条目),会找不到对应缓存 - 遍历所有缓存页:如果不确定目标数据在哪一页,需要遍历所有已缓存的分页条目
修正后的代码:
async onQueryStarted(updatedItem, { dispatch, getState }) { const queryKeys = Object.keys(getState().api.queries).filter(k => k.includes('getOrderList')); queryKeys.forEach(key => { const { queryArgs } = getState().api.queries[key]; dispatch( ApiSlice.util.updateQueryData('getOrderList', queryArgs, draft => { const targetItem = draft.find(item => item.id === updatedItem.id); if (targetItem) { Object.assign(targetItem, updatedItem); } }) ); }); }
如果明确知道目标数据所在的页码,也可以直接指定查询参数更新:
// 直接更新第1页的缓存 dispatch( ApiSlice.util.updateQueryData('getOrderList', { page: 1 }, draft => { const item = draft.find(item => item.b === 1); if (item) item.b = 5; }) );
内容的提问来源于stack exchange,提问作者Amir Rezvani
相关产品推荐
相关产品推荐

