У меня возникли проблемы с пониманием поведения кэширования при запросе 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 пуста при переключении на следующую конечную точку и в идеале избавление от ненужного аргумента) будет оценена по достоинству. ваше здоровье.





В основном это работает так, как ожидалось, однако при переключении между наборы данных: предыдущий набор данных все равно будет отображаться во время ожидания для завершения следующей выборки. Я ожидал, что здесь будет пусто поскольку это другая конечная точка, которая еще не получена?
По сути, вы нарушаете Правила хуков React, вызывая хуки useQuery по условию, но я подозреваю, что каждый экземпляр настолько похож, что React не знает, что в последующем цикле рендеринга был вызван технически другой крючок. Не делая полного погружения в выполнение кода, я считаю, что происходит примерно следующее:
api.endpoints.fetchOdd.useQuery работает и загружается. Его данные о результатах кэшируются и запускают повторную отрисовку компонента App, чтобы результат отображался.dataset обновляется с «нечетного» на «четное» и запускает обновление компонента.api.endpoints.fetchEven.useQuery, и поскольку вызывается «тот же крючок» (тот же крючок, тот же порядок и т. д.), текущее значение для вызова хука в этой позиции возвращается в пользовательский интерфейс, например «нечетный результат», хотя в то же время 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;
Привет, спасибо за ответ. Да, это имеет смысл, я думаю, мне нужно еще немного изучить хуки. ваше здоровье.