我无法理解 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 为空,并且最好摆脱不需要的参数)的帮助将不胜感激。干杯。
这基本上按预期工作 - 但是当在 等待时仍会显示之前的数据集 以便下一次获取完成。我本以为这是空的 因为它是针对尚未获取的不同端点?
通过有条件地调用 useQuery
钩子,你基本上打破了
React 的 Hooks 规则,但我怀疑每个实例都足够相似,以至于 React 不知道在后续渲染周期中调用了 技术上不同的 钩子。在没有完全深入研究代码执行的情况下,我相信这大致就是正在发生的事情:
api.endpoints.fetchOdd.useQuery
挂钩运行并加载。其结果数据被缓存并触发 App
组件重新渲染,以便显示结果。dataset
状态从“奇”更新为“偶”并触发组件更新。api.endpoints.fetchEven.useQuery
钩子,并且由于调用了“相同的钩子”(相同的钩子、相同的顺序等),该位置的钩子调用的当前值将返回给 UI,例如“奇怪的结果”,同时 RTK Query 知道查询状态和元数据并实际获取数据。它的结果也会被缓存并触发 App
组件重新渲染,以便显示新结果。此外,任何逻辑都不需要
的参数,但是 如果我对每个端点没有不同的参数,那么第二个 fetch 根本不会运行,只是处于挂起状态。useQuery
我认为这与上面的情况有关,因为查询参数没有改变,所以它不会重新运行。在参数
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;