Подключение RTK Query API с редуктором и селектором

Я думаю, что мне что-то не хватает в отношении инструментов Redux и RTK Query. Я также использую для этого RTK Query OpenAPI codegen.

Прямо сейчас у меня есть API, который выглядит так -›

export const api = generatedApi.enhanceEndpoints({
  endpoints: {
    getMaterials: {
      transformResponse: response => normalize(response),
    },
  },
})

Это возвращает мне нормализованные данные в моем компоненте:

const Materials = () => {
  const { data, isLoading, error } = useGetMaterialsQuery()

  /*
    Cool this gives me data back like:
    {
      [id]: {
        id,
        prop1: 'blah',
        prop2: 'blah2'
      }
    }
  */

  console.log(data)

  // but now I want to structure this data differently using selector

  const newDataStructure = useSelector(addSomeMetaDataAndStructureDifferentlySelector)

  return <MyComponent structuredData={newDataStructure} />
}

Но когда я смотрю на состояние в этом селекторе, это выглядит так:

фрагмент данных

Когда в селекторе я действительно хочу использовать что-то вроде -›

const addSomeMetaDataAndStructureDifferentlySelector = state => 
    // create new data structure from state.materials.byId that I will pass to `MyComponent`

Мой магазин сейчас выглядит вот так -›

import { configureStore } from '@reduxjs/toolkit'
import { setupListeners } from '@reduxjs/toolkit/query'
import { api } from 'gen/rtk-openapi'
// import materialsReducer from 'state/materials/materialsSlice'

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

setupListeners(store.dispatch)

export default store

Итак, мне нужно передать data непосредственно из useGetMaterialsQuery в функцию и просто преобразовать ее?

Или я могу каким-то образом создать новый фрагмент редуктора, который каким-то образом правильно инициализирует данные, чтобы я мог получить доступ к state.materials.byId в селекторе?

Или я что-то принципиально упускаю здесь?


person Evan    schedule 23.07.2021    source источник


Ответы (1)


Вы пропустили важный момент: RTK-Query не нормализованный кеш, а кеш документа.

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

Это может показаться недостатком, но создание реального нормализованного кеша почти невозможно в качестве универсальной библиотеки, особенно для чего-то неоднозначного, такого как API REST. Даже для GraphQL это очень сложная проблема, и даже решения, специализирующиеся на GraphQL (например, apollo), имеют много проблем и заканчиваются большим количеством написанного от руки кода для обработки таких случаев, как добавление/удаление из коллекций.

Итак, в конце концов, у вас остается два варианта: написать собственное нормализованное решение для кэширования вручную, явно ориентированное на ваши структуры данных, или использовать кэш документов.

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

Как правило, я бы рекомендовал не копировать эти данные в рукописные фрагменты. Таким образом, вы потеряете множество преимуществ RTK-Query, например, отслеживание подписки и автоматическую очистку кеша после того, как компоненты больше не будут использовать значение через 60 секунд. Это может показаться необычным после использования Redux с рукописными фрагментами некоторое время, но в большинстве ситуаций это работает очень хорошо — с гораздо меньшим количеством кода.

Что касается того, как его использовать: как правило, вы просто вызываете свой useGetMaterialsQuery() во всех компонентах, которым нужны материалы, и просто отфильтровываете то, что вам нужно в вашем компоненте, или используете опцию selectFromResult, чтобы просто выбрать то, что вам действительно нужно.

person phry    schedule 23.07.2021
comment
как используется selectFromResult? - person Evan; 26.07.2021