6

我想我在 Redux 和 RTK 查询工具方面遗漏了一些东西。我也在为此使用 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直接将 from传递useGetMaterialsQuery给函数并对其进行转换?

或者我可以以某种方式创建一个新的 reducer 切片,以某种方式正确初始化数据,以便我可以state.materials.byId在选择器中访问?

还是我从根本上在这里遗漏了什么?

4

1 回答 1

8

您错过了重要的一点:RTK-Query 不是规范化缓存,而是文档缓存。

它使用请求参数作为缓存键来缓存您的端点和对这些端点的每个请求。这些响应中的每一个都被视为“文档”并单独缓存。

这似乎是一个缺点,但是作为一个通用库几乎不可能实现真正的“规范化”缓存,尤其是对于像 REST api 这样模棱两可的东西。即使对于 GraphQL 来说,这也是一个非常困难的问题,甚至专门针对 GraphQL 的解决方案(如 apollo)也存在很多问题,并且最终需要大量手写代码来处理诸如从集合中添加/删除之类的情况。

因此,最后,您有两个选择:手动编写自己的规范化缓存解决方案,明确针对您的数据结构或使用文档缓存。

在大多数情况下,文档缓存就足够了。这就是 RTK-Query 的用武之地,它试图为您提供尽可能多的工具来保持文档之间的数据“同步”:自动重新获取以及您希望避免手动乐观更新以操作特定缓存条目的选项.

一般来说,我建议不要将该数据复制到手写切片。这样你会失去 RTK-Query 的很多好处,例如订阅跟踪和在 60 秒后没有更多组件使用值后的自动缓存清理。在将 Redux 与手写切片一起使用一段时间后,这听起来可能并不常见,但它在大多数情况下都能很好地工作 - 代码少得多。

至于如何使用:一般情况下,你只需useGetMaterialsQuery()在所有需要材料的组件中调用你的,然后在你的组件中过滤掉你需要的东西,或者使用selectFromResult选项来选择你真正需要的东西。

于 2021-07-23T23:15:47.943 回答