RTK端点之间的查询缓存

问题描述 投票:0回答:1

我无法理解 RTK 查询的缓存行为。


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) => ({
    fetchOdd: build.query<number[], number>({query: () => 'odd', providesTags: ['odd']}),
    fetchEven: build.query<number[], number>({query: () => 'even', providesTags: ['even']})
  })
});

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


const App = () => {

  const [dataset, setDataset] = useState('odd'); 
  const result = dataset == 'odd' ? api.endpoints.fetchOdd.useQuery(1) : api.endpoints.fetchEven.useQuery(2)
  return (
    <div>
      <button onClick={() => setDataset(dataset == 'odd' ? 'even' : 'odd')}>{dataset}</button>
      { result.data?.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>);  

这基本上按预期工作 - 但是,在数据集之间切换时,在等待下一次获取完成时,前一个数据集仍将显示。我本以为它是空的,因为它用于尚未获取的不同端点?

此外,任何逻辑都不需要 useQuery 的参数,但是如果我没有为每个端点提供不同的参数,那么第二次提取将根本不会运行,只是处于挂起状态。

任何帮助理解这种行为或实现所需结果(切换到下一个端点时 result.data 为空,并且最好摆脱不需要的参数)的帮助将不胜感激。干杯。

reactjs typescript redux rtk-query
1个回答
0
投票

这基本上按预期工作 - 但是当在 等待时仍会显示之前的数据集 以便下一次获取完成。我本以为这是空的 因为它是针对尚未获取的不同端点?

通过有条件地调用 useQuery 钩子,你基本上打破了

React 的 Hooks 规则
,但我怀疑每个实例都足够相似,以至于 React 不知道在后续渲染周期中调用了 技术上不同的 钩子。在没有完全深入研究代码执行的情况下,我相信这大致就是正在发生的事情:

  • api.endpoints.fetchOdd.useQuery
    挂钩运行并加载。其结果数据被缓存并触发
    App
    组件重新渲染,以便显示结果。
  • dataset
    状态从“奇”更新为“偶”并触发组件更新。
  • 调用
    api.endpoints.fetchEven.useQuery
    钩子,并且由于调用了“相同的钩子”(相同的钩子、相同的顺序等),该位置的钩子调用的当前值将返回给 UI,例如“奇怪的结果”,同时 RTK Query 知道查询状态和元数据并实际获取数据。它的结果也会被缓存并触发
    App
    组件重新渲染,以便显示新结果。

此外,任何逻辑都不需要

useQuery
的参数,但是 如果我对每个端点没有不同的参数,那么第二个 fetch 根本不会运行,只是处于挂起状态。

我认为这与上面的情况有关,因为查询参数没有改变,所以它不会重新运行。在参数

1
2
之间切换可以超越这个并触发第二个查询运行。

任何有助于理解这种行为或实现预期结果的帮助 (切换到下一个端点时

result.data
为空,理想情况下 摆脱不必要的争论)将不胜感激。

我建议无条件地调用两个钩子(无论如何这是规则)。如果需要,请使用

skip
选项有条件地运行查询。请参阅条件获取

示例:

const [dataset, setDataset] = useState("odd");

const evenResult = api.endpoints.fetchEven.useQuery(undefined, {
  skip: dataset !== "even",
});
const oddResult = api.endpoints.fetchOdd.useQuery(undefined, {
  skip: dataset !== "odd",
});

const result = dataset == "odd" ? oddResult : evenResult;

或使用生成的查询挂钩:

const [dataset, setDataset] = useState("odd");

const evenResult = api.useFetchEvenQuery(undefined, {
  skip: dataset !== "even",
});
const oddResult = api.useFetchOddQuery(undefined, {
  skip: dataset !== "odd",
});

const result = dataset == "odd" ? oddResult : evenResult;
© www.soinside.com 2019 - 2024. All rights reserved.