Redux RTK中如何向endpoint.select()传参调用getSelectors
问题核心
getSetups是带documentId参数的查询接口,RTK Query会按照传入的查询参数分块存储缓存结果,直接无参调用.select()无法匹配到对应documentId的缓存数据,以下是两种不需要查询全量数据再过滤的实现方案:
方案1:动态传参匹配对应参数的缓存(优先推荐)
直接给endpoint.select()传入目标documentId,配合createSelector支持动态传参,直接命中对应参数的缓存,完全跟随RTK Query的缓存生命周期,不需要额外维护状态。
import { createSelector } from '@reduxjs/toolkit' // 接收state和documentId两个入参,动态读取对应documentId的查询缓存 const selectSetupsDataByDocumentId = createSelector( [ (state, documentId) => setupsApiSlice.endpoints.getSetups.select(documentId)(state) ], (setupsResult) => setupsResult?.data ?? initialState ) // 导出绑定了归一化逻辑的选择器,调用时传入documentId即可 export const { selectAll: selectAllSetupsByDocId, selectById: selectSetupByIdByDocId, selectIds: selectSetupIdsByDocId, } = setupsAdapter.getSelectors((state, documentId) => selectSetupsDataByDocumentId(state, documentId))
调用示例
// 在组件中使用useSelector选数 const currentDocId = 'xxx' const currentDocSetups = useSelector(state => selectAllSetupsByDocId(state, currentDocId))
这个方案不需要额外写状态同步逻辑,当对应documentId的查询缓存被RTK Query自动清理时,selector会自动回退到初始状态,没有额外维护成本。
方案2:独立维护全局归一化Setups切片(无需调用endpoint.select())
如果不想每次选数都传documentId,可以单独创建一个基于entityAdapter的Redux切片,监听RTK Query请求的成功action,把所有接口返回的setups数据自动同步到全局归一化状态中,后续选数直接读这个独立切片即可,完全不需要依赖endpoint.select()。
实现步骤
- 首先创建独立的setups切片,监听接口请求成功的动作同步数据:
import { createSlice } from '@reduxjs/toolkit' import { setupsAdapter } from './your-adapter-path' // 你预先定义的setupsAdapter const setupsSlice = createSlice({ name: 'setups', initialState: setupsAdapter.getInitialState(), reducers: {}, extraReducers: (builder) => { // 监听getSetups请求成功,把返回的setups列表写入全局归一化状态 builder.addMatcher( setupsApiSlice.endpoints.getSetups.matchFulfilled, (state, { payload }) => { // payload是接口返回的当前documentId下的setups数组,直接合并到全局状态 setupsAdapter.upsertMany(state, payload) } ) // 增/删/改的mutation也可以在这里加对应的匹配器,同步更新全局状态 // 比如新增成功调用setupsAdapter.addOne,删除成功调用setupsAdapter.removeOne即可 } }) export default setupsSlice.reducer
- 把这个切片的reducer加入Redux Store的配置中:
export const store = configureStore({ reducer: { // 其他reducer... setups: setupsReducer, [apiSlice.reducerPath]: apiSlice.reducer, }, // 其他middleware配置... })
- 直接基于全局setups切片生成选择器,不需要调用
endpoint.select():
export const { selectAll: selectAllSetups, selectById: selectSetupById, selectIds: selectSetupIds, } = setupsAdapter.getSelectors(state => state.setups)
方案说明
- 优点:所有setups数据全局归一化存储,选数时不需要传
documentId,跨文档的setups数据可以直接复用 - 注意点:需要手动同步增/删/改操作后的状态,且全局状态不会跟随RTK Query的缓存自动清理,如果数据量较大需要自己加清理逻辑。
内容的提问来源于stack exchange,提问作者Oriol
相关产品推荐
相关产品推荐

