RTK Query优化:避免createItem后重复调用getBasket查询
问题描述
我用Redux Toolkit的createApi开发时,碰到createItem端点会触发不必要的getBasket API调用。createItem这个mutation会更新购物车(Basket),并且响应里会返回更新后的完整购物车数据。我本来用了带"Basket"标签和"LIST" ID的invalidatesTags来同步缓存,但执行完createItem后还是会重复调用getBasket,完全没必要。
当前代码实现:
export const basketApi = createApi({ reducerPath: "basketApi", baseQuery: fetchBaseQuery({ baseUrl: "https://localhost:5000/api/", credentials: "include", }), tagTypes: ["Basket"], endpoints: (builder) => ({ getBasket: builder.query<Basket, void>({ query: () => `basket`, providesTags: [{ type: "Basket", id: "LIST" }], }), createItem: builder.mutation<Basket, { productId: number; qty?: number }>({ query: ({ productId, qty }) => ({ url: `Basket?productId=${productId}&quantity=${qty || 1}`, method: "POST", }), invalidatesTags: [{ type: "Basket", id: "LIST" }], }), }), });
我试过下面的写法,但不确定在invalidatesTags里调用dispatch是否正确:
export const basketApi = createApi({ reducerPath: "basketApi", baseQuery: fetchBaseQuery({ baseUrl: "https://localhost:5000/api/", credentials: "include", }), tagTypes: ["Basket"], endpoints: (builder) => ({ getBasket: builder.query<Basket, void>({ query: () => `basket`, providesTags: [{ type: "Basket", id: "LIST" }], }), createItem: builder.mutation<Basket, { productId: number; qty?: number }>({ query: ({ productId, qty }) => ({ url: `Basket?productId=${productId}&quantity=${qty || 1}`, method: "POST", }), invalidatesTags: (result) => { store.dispatch(setBasket(result)); return []; }, }), }), });
解决方案
核心思路是直接用mutation返回的更新后数据覆盖getBasket的缓存,而非通过invalidatesTags触发缓存失效导致重复请求。
推荐实现方式
使用onQueryStarted钩子,在请求成功后直接更新缓存:
export const basketApi = createApi({ reducerPath: "basketApi", baseQuery: fetchBaseQuery({ baseUrl: "https://localhost:5000/api/", credentials: "include", }), tagTypes: ["Basket"], endpoints: (builder) => ({ getBasket: builder.query<Basket, void>({ query: () => `basket`, providesTags: [{ type: "Basket", id: "LIST" }], }), createItem: builder.mutation<Basket, { productId: number; qty?: number }>({ query: ({ productId, qty }) => ({ url: `Basket?productId=${productId}&quantity=${qty || 1}`, method: "POST", }), async onQueryStarted(args, { dispatch, queryFulfilled }) { try { const { data: updatedBasket } = await queryFulfilled; // 直接更新getBasket的缓存数据 dispatch( basketApi.util.updateQueryData('getBasket', undefined, () => updatedBasket) ); } catch (err) { // 可按需处理请求失败逻辑 } }, // 不需要再通过标签失效触发请求 invalidatesTags: [], }), }), });
简化写法(无需处理失败逻辑)
如果不需要处理请求失败的场景,也可以用updateQueryData直接更新:
createItem: builder.mutation<Basket, { productId: number; qty?: number }>({ query: ({ productId, qty }) => ({ url: `Basket?productId=${productId}&quantity=${qty || 1}`, method: "POST", }), updateQueryData: (cache, result) => { cache.setQueryData('getBasket', undefined, result); }, invalidatesTags: [], }),
你的尝试存在的问题
直接在invalidatesTags里调用store.dispatch是不规范的:
invalidatesTags的设计目的是返回要失效的标签集合,不是执行副作用的地方- 绕开RTK Query的缓存管理逻辑直接操作store,可能导致缓存与实际状态不一致
内容的提问来源于stack exchange,提问作者Eli
相关产品推荐
相关产品推荐

