React+RTK注册功能出现invalidatesTags未定义的TypeError错误
错误信息
TypeError: Cannot read properties of undefined (reading 'invalidatesTags') at calculateProvidedByThunk (buildThunks.ts:629:1) at handler (invalidationByTags.ts:31:1) at index.ts:120:1 at index.ts:102:1 at index.ts:102:1 at index.js:20:1 at immutableStateInvariantMiddleware.ts:253:1 at dispatch (redux.js:691:1) at createAsyncThunk.ts:682:1 at step (index.ts:4:1)
问题根源
1. RTK Query端点嵌套定义错误
在authApi中,你将register mutation嵌套在了login mutation内部,setNewPassword嵌套在了resetPassword mutation内部。RTK Query要求每个endpoint必须是builder直接返回的顶级属性,这种嵌套结构会导致RTK无法正确识别和注册这些mutation,触发内部逻辑时找不到对应的配置项,从而抛出invalidatesTags读取错误。
2. 多个API实例reducerPath重复
authApi和adminApi的reducerPath都设置为"api",RTK Query要求每个createApi实例的reducerPath必须唯一,否则两个API的状态会在Redux store中相互覆盖,引发内部状态处理的异常。
修复步骤
第一步:修正authApi的端点定义
将嵌套的mutation改为顶级端点:
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; export const authApi = createApi({ reducerPath: "authApi", // 修改为唯一的reducerPath baseQuery: fetchBaseQuery({ baseUrl: process.env.REACT_APP_API_ROOT_URL }), endpoints: (builder) => ({ login: builder.mutation({ query: (body) => ({ url: "/users/login", method: "post", body, }), }), // 改为顶级mutation register: builder.mutation({ query: (body) => ({ url: "/users/register", method: "post", body, }), }), resetPassword: builder.mutation({ query: (body) => ({ url: "/resetPassword", method: "PATCH", body, }), }), // 改为顶级mutation,参数调整为单个对象(RTK mutation仅支持单个参数) setNewPassword: builder.mutation({ query: ({ body, token }) => ({ url: `/resetPassword/${token}`, method: "PATCH", body, }), }), }), }); export const { useLoginMutation, useRegisterMutation, useResetPasswordMutation, useSetNewPasswordMutation, } = authApi;
第二步:修正adminApi的reducerPath及请求头配置
将adminApi的reducerPath改为唯一值,同时修复prepareHeaders的返回逻辑:
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; export const adminApi = createApi({ reducerPath: "adminApi", // 修改为唯一的reducerPath baseQuery: fetchBaseQuery({ baseUrl: process.env.REACT_APP_API_ROOT_URL, prepareHeaders: (headers, { getState }) => { const token = getState().auth.JWT; if (token) { headers.set("authorization", `Bearer ${token}`); } return headers; // 确保始终返回headers对象,避免无token时返回undefined }, }), tagTypes: ["Categories", "Products", "Tva", "Product"], endpoints: (builder) => ({ // 其余端点代码保持不变 getCategoriesAdmin: builder.query({ query: () => "/categories/getAllAdmin", providesTags: ["Categories", "Products"], }), getProductsAdmin: builder.query({ query: () => "/products/getAllAdmin", providesTags: ["Categories", "Products"], }), getOneProductAdmin: builder.query({ query: (id) => `/products/getOneAdmin/${id}`, }), getTvaAdmin: builder.query({ query: () => "/TVA/getAllAdmin", providesTags: ["Tva"], }), addProduct: builder.mutation({ query: (body) => ({ url: "/products/createOne", method: "post", body, }), invalidatesTags: ["Categories", "Products"], }), updateProductPut: builder.mutation({ query: (o) => ({ url: `/products/updateOnePut/${o.id}`, method: "PUT", body: o.body, }), invalidatesTags: ["Categories", "Products"], }), updateProductPatch: builder.mutation({ query: (o) => ({ url: `/products/updateOnePatch/${o.id}`, method: "PATCH", body: o.body, }), invalidatesTags: ["Categories", "Products"], }), }), }); export const { useGetCategoriesAdminQuery, useGetTvaAdminQuery, useGetProductsAdminQuery, useAddProductMutation, useUpdateProductPutMutation, useUpdateProductPatchMutation, useGetOneProductAdminQuery, } = adminApi;
第三步:更新Store中的reducer配置
对应修改store中的reducer键名,匹配新的reducerPath:
import { configureStore, combineReducers } from "@reduxjs/toolkit"; import authReducer from "./slices/authSlice"; import adminReducer from "./slices/adminSlice"; import shopReducer from "./slices/shopSlice"; import { persistReducer, persistStore } from "redux-persist"; import thunk from "redux-thunk"; import storage from "redux-persist/lib/storage"; import { shopApi } from "./api/shopApi"; import { authApi } from "./api/authApi"; import { adminApi } from "./api/adminApi"; const persistConfig = { key: "root", storage, }; const rootReducer = combineReducers({ auth: authReducer, admin: adminReducer, shop: shopReducer, [authApi.reducerPath]: authApi.reducer, [shopApi.reducerPath]: shopApi.reducer, [adminApi.reducerPath]: adminApi.reducer, }); const persistedReducer = persistReducer(persistConfig, rootReducer); export const store = configureStore({ reducer: persistedReducer, middleware: (getDefaultMiddleware) => { const allMiddleware = [ authApi.middleware, shopApi.middleware, adminApi.middleware, thunk, ]; return getDefaultMiddleware({ serializableCheck: false }).concat( ...allMiddleware ); }, }); export const persistor = persistStore(store);
验证
修复后,调用registerUser时将不再触发该错误,同时所有API的状态会被正确隔离,避免互相干扰。
内容的提问来源于stack exchange,提问作者Marie-Lou Le Jan
相关产品推荐
相关产品推荐

