如何解决使用 redux reducer 和 selector 连接 RTK Query API
我想我在 Redux 和 RTK 查询工具方面遗漏了一些东西。我也在为此使用 RTK 查询 OpenAPI 代码生成器。
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
传递到一个函数中并对其进行转换?
或者我可以以某种方式创建一个新的 reducer 切片,以某种方式正确地使用数据进行初始化,以便我可以在选择器中访问 state.materials.byId
?
还是我在这里遗漏了什么?
解决方法
您错过了一个重要的部分:RTK-Query is not a normalized cache,但是文档缓存。
它使用请求参数作为缓存键来缓存您的端点和对这些端点的每个请求。这些响应中的每一个都被视为一个“文档”并单独缓存。
这似乎是一个缺点,但作为一个通用库,做一个真正的“规范化”缓存几乎是不可能的,尤其是对于 REST api 之类的不明确的东西。即使对于 GraphQL,这也是一个非常困难的问题,甚至专门针对 GraphQL 的解决方案(如 apollo)也有很多问题,最终需要大量手写代码来处理诸如从集合中添加/删除等情况。
所以最后,您有两个选择:手动编写自己的规范化缓存解决方案,明确针对您的数据结构或使用文档缓存。
在大多数情况下,文档缓存就足够了。这就是 RTK-Query 的用武之地,它试图为您提供尽可能多的工具来保持文档之间的数据“同步”:automated refetching 以及您想要避免的选项 manual optimistic updates操作特定的缓存条目。
一般来说,我建议不要将该数据复制到手写切片中。这样一来,您将失去 RTK-Query 的许多好处,例如订阅跟踪和自动缓存清理,因为 60 秒后不再有组件使用某个值。 在使用 Redux 和手写切片一段时间后,这听起来可能并不常见,但它在大多数情况下都能很好地工作 - 代码少得多。
至于如何使用:一般情况下,您只需在所有需要材料的组件中调用您的useGetMaterialsQuery()
,然后过滤掉您的组件中需要的内容,或者使用selectFromResult
选项仅选择您真正需要的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。