You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:25:25