RTK Query injectEndpoints执行顺序报错及最佳解决方案咨询
推荐解决方案(按优先级排序)
1. 统一集中注入端点
这是最符合中心化设计原则的方案,完全规避执行顺序问题:
不要将injectEndpoints逻辑分散到各业务文件,将所有端点定义统一收敛到API层,在导出baseApi实例前完成所有端点的注入,保证任何文件导入baseApi时,所有端点都已完成注册。
改造示例:
// api.js import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' import draftableEndpoints from './endpoints/draftables' // 导入其他所有业务端点定义 const baseApi = createApi({ reducerPath: "baseApi", baseQuery: fetchBaseQuery({ baseUrl: Globals.BASE_URL + "/api", prepareHeaders, }), endpoints: () => ({}), }); // 统一注入所有端点 baseApi.injectEndpoints(draftableEndpoints) // 继续注入其他业务端点 export default baseApi;
对应的端点定义文件调整为导出配置即可:
// endpoints/draftables.js export default { endpoints: build => ({ getDraftables: build.query({ query: ({ draftgroupId, gameTypeId }) => "whatever/url", transformResponse: ({ data: players }) => players.map(transformApiPlayer), }), }), }
2. 用onCacheEntryAdded替代extraReducers匹配
完全解耦切片和API端点的依赖顺序,不需要在切片里匹配请求状态:
在端点定义中添加onCacheEntryAdded钩子,请求成功后直接dispatch切片的同步action更新状态即可。
// draftables.js 端点定义 getDraftables: build.query({ query: ({ draftgroupId, gameTypeId }) => "whatever/url", transformResponse: ({ data: players }) => players.map(transformApiPlayer), async onCacheEntryAdded(arg, { dispatch, cacheDataLoaded }) { const { data: players } = await cacheDataLoaded // 调用currentDraftSlice暴露的setPlayers同步action dispatch(setPlayers(players)) } })
切片不需要再写extraReducers,正常定义普通reducer即可:
// currentDraftSlice.js const currentDraftSlice = createSlice({ name: "currentDraft", initialState, reducers: { setPlayers: (state, action) => { state.players = action.payload.map(p => ({ ...p, drafted: false, })) } } }) export const { setPlayers } = currentDraftSlice.actions
3. 可选兜底方案:加存在性判断
如果要保留现有extraReducers的写法,可以加判断避免访问undefined属性:
extraReducers: builder => { // 先判断端点是否已注入,再添加匹配器 if (baseApi.endpoints.getDraftables) { builder.addMatcher( baseApi.endpoints.getDraftables.matchFulfilled, (state, action) => { state.players = action.payload.map(p => ({ ...p, drafted: false, })); } ); } }
额外优化建议
如果你的本地players状态不需要跨请求共享修改,也可以直接在查询时通过selectFromResult处理,完全不需要额外的切片存储:
const { data } = useGetDraftablesQuery(params, { selectFromResult: ({ data }) => ({ data: data?.map(p => ({...p, drafted: false})) }) })
内容的提问来源于stack exchange,提问作者Jonathan Tuzman
相关产品推荐
相关产品推荐

