Подключение RTK Query API с редуктором и селектором redux
Я думаю, что мне что-то не хватает в отношении инструментов Redux и RTK Query. Я также использую для этого кодогенератор RTK Query OpenAPI.
Прямо сейчас у меня есть 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
в селекторе?
Или мне здесь что-то принципиально не хватает?
1 ответ
Вы пропустили важный момент: RTK-Query - это не нормализованный кеш , а кеш документа.
Он кэширует ваши конечные точки и каждый запрос к ним, используя аргументы запроса в качестве ключей кеша. Каждый из этих ответов обрабатывается как «документ» и кэшируется отдельно.
Это может показаться недостатком, но создание реального «нормализованного» кеша в качестве общей библиотеки практически невозможно, особенно для чего-то неоднозначного, как REST apis. Даже для GraphQL это очень сложная проблема, и даже решения, специализированные на GraphQL (например, apollo), имеют множество проблем и заканчиваются большим количеством рукописного кода для обработки таких случаев, как добавление / удаление из коллекций.
Итак, в конце у вас остается два варианта: написать собственное нормализованное решение для кэширования вручную, явно ориентированное на ваши структуры данных, или использовать кеш документов.
В большинстве случаев кеша документов достаточно. И именно здесь появляется RTK-Query, который пытается предоставить вам как можно больше инструментов для «синхронизации» данных между вашими документами: автоматическая повторная выборка и где вы хотите избежать этого, возможность выполнять оптимистические обновления вручную для управления определенными записями в кеше. .
Как правило, я бы не рекомендовал копировать эти данные в рукописные фрагменты. Таким образом, вы потеряете множество преимуществ RTK-Query, например, отслеживание подписки и автоматическую очистку кеша после того, как ни один из компонентов не использует значение через 60 секунд. Это может показаться необычным после использования Redux с рукописными фрагментами в течение некоторого времени, но в большинстве ситуаций он работает очень хорошо - с гораздо меньшим количеством кода.
Что касается того, как его использовать: как правило, вы просто звоните своему
useGetMaterialsQuery()
во всех компонентах, которые нуждаются в материалах, и просто отфильтруйте то, что вам нужно в своем компоненте, или используйте
selectFromResult
возможность просто выбрать то, что вам действительно нужно.