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

RTK Query跨端点缓存行为疑问及代码问题求助

解决RTK Query缓存与请求异常的两个问题

问题1:切换数据集时pending状态仍显示旧数据

原因

你通过条件分支调用不同的useQuery hook,违反了React Hook的核心规则——必须在组件顶层无条件调用hook。这种写法会导致React无法正确跟踪hook的状态,RTK Query的缓存也不会被及时清理,新请求pending时依然会渲染旧查询的缓存数据。另外RTK Query默认的stale-while-revalidate机制也会保留旧数据,但核心问题还是hook的条件调用导致的异常。

解决方案

不要在条件中切换useQuery调用,而是在组件顶层同时调用两个查询的useQuery,再根据当前状态决定展示哪组数据。同时判断当前选中查询的加载状态,pending时不渲染任何数据。


问题2:不传不同参数时第二个请求一直pending

原因

同样是违反React Hook调用规则导致的异常:条件调用hook会让React无法正确维护hook的调用顺序,当两个useQuery使用相同参数时,组件渲染逻辑混乱,导致第二个请求无法正常完成,一直处于pending状态。另外你的两个endpoint的query函数完全忽略了传入的参数,属于无意义的传参。

解决方案

  1. 遵守Hook规则,在组件顶层同时调用两个useQuery;
  2. 将endpoint的参数类型改为void,不需要传入任何参数,避免无意义的传参。

修改后的完整代码

import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import { createApi } from '@reduxjs/toolkit/query/react';
import { combineReducers, configureStore } from '@reduxjs/toolkit';

const baseQuery = async (arg: string) => {
  await new Promise(resolve => setTimeout(resolve, 5000)); 
  return { data: arg === 'odd' ? [1, 2, 3] : [2, 4, 6]}; 
}; 

const api = createApi({
  baseQuery,
  endpoints: (build) => ({
    // 参数类型改为void,无需传入参数
    fetchOdd: build.query<number[], void>({
      query: () => 'odd',
      providesTags: ['odd']
    }),
    fetchEven: build.query<number[], void>({
      query: () => 'even',
      providesTags: ['even']
    })
  })
});

const store = configureStore({
  reducer: { [api.reducerPath]: api.reducer },
  middleware: (getDefault) => getDefault().concat(api.middleware)
});

const App = () => {
  const [dataset, setDataset] = useState('odd'); 
  
  // 顶层同时调用两个useQuery,符合Hook规则
  const { data: oddData, isLoading: isOddLoading } = api.endpoints.fetchOdd.useQuery();
  const { data: evenData, isLoading: isEvenLoading } = api.endpoints.fetchEven.useQuery();

  // 根据当前数据集匹配对应的数据和加载状态
  const currentData = dataset === 'odd' ? oddData : evenData;
  const currentIsLoading = dataset === 'odd' ? isOddLoading : isEvenLoading;

  return (
    <div>
      <button onClick={() => setDataset(dataset === 'odd' ? 'even' : 'odd')}>
        {dataset}
      </button>
      {/* 加载状态时不渲染数据,实现pending时内容为空的需求 */}
      {!currentIsLoading && currentData?.map(d => <div key={d}>{d}</div>)}
    </div>
  );
}

const container = document.getElementById('app-root')!;
const root = createRoot(container);
root.render(<Provider store={store}><App/></Provider>);  

内容的提问来源于stack exchange,提问作者Martin McCann

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 05:38:12