Кэширование RTK-запросов между конечными точками

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

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
0
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В основном это работает так, как ожидалось, однако при переключении между наборы данных: предыдущий набор данных все равно будет отображаться во время ожидания для завершения следующей выборки. Я ожидал, что здесь будет пусто поскольку это другая конечная точка, которая еще не получена?

По сути, вы нарушаете Правила хуков 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;

Привет, спасибо за ответ. Да, это имеет смысл, я думаю, мне нужно еще немного изучить хуки. ваше здоровье.

Martin McCann 11.05.2024 11:54

Другие вопросы по теме