RTK Query初始化后如何覆盖BaseUrl?(Pact集成测试场景)
解决RTK Query初始化后修改BaseUrl用于Pact测试的问题
我刚好碰到过类似的困扰——RTK Query默认会缓存初始化时的baseQuery配置,直接改固定的GraphQLClient实例根本没用。下面给你两种亲测有效的解决方案:
方法一:用可修改的Client引用动态切换地址
这种方法最简单,只需要把固定的Client实例改成一个可更新的引用容器,让baseQuery每次调用都取最新的Client:
修改基础API代码
import { createApi } from '@reduxjs/toolkit/query/react'; import { graphqlRequestBaseQuery } from '@rtk-query/graphql-request-base-query'; import { GraphQLClient } from 'graphql-request'; // 用一个对象容器存Client,方便后续替换 export const clientRef = { current: new GraphQLClient('http://localhost:12355/graphql') }; export const api = createApi({ baseQuery: graphqlRequestBaseQuery({ // 每次调用baseQuery时,都取当前最新的Client实例 client: () => clientRef.current }), endpoints: () => ({}), });
在测试中替换Mock地址
it('works with rtk', async () => { // 先拿到Pact Mock服务器的地址(根据你的Pact配置获取,比如 pactMockServer.url) const pactMockUrl = 'http://localhost:XXXX/graphql'; // 替换成你的Mock实际地址 // 直接替换clientRef里的实例,指向Mock服务器 clientRef.current = new GraphQLClient(pactMockUrl); const reducer = { [api.reducerPath]: api.reducer, }; const { store } = setupStoreAndPersistor({ enableLog: true, rootReducer: reducer, isProduction: false, }); // 发起请求并等待完成(用unwrap()替代setTimeout,更可靠) await store.dispatch(api.endpoints.GetModules.initiate()).unwrap(); const state = store.getState(); const queryResult = state.api.queries['GetModules(undefined)']; expect(queryResult?.data).toEqual({modules: []}); });
方法二:从Store动态获取BaseUrl(更符合Redux思想)
如果想更贴合Redux的状态管理模式,可以把BaseUrl存在Store里,让baseQuery每次都从Store读取最新地址:
1. 创建API配置Slice
import { createSlice } from '@reduxjs/toolkit'; const apiConfigSlice = createSlice({ name: 'apiConfig', initialState: { baseUrl: 'http://localhost:12355/graphql', }, reducers: { setApiBaseUrl: (state, action) => { state.baseUrl = action.payload; }, }, }); export const { setApiBaseUrl } = apiConfigSlice.actions; export const apiConfigReducer = apiConfigSlice.reducer;
2. 修改RTK Query的baseQuery配置
import { createApi } from '@reduxjs/toolkit/query/react'; import { graphqlRequestBaseQuery } from '@rtk-query/graphql-request-base-query'; import { GraphQLClient } from 'graphql-request'; export const api = createApi({ baseQuery: async (args, apiContext, extraOptions) => { // 从Store中获取最新的BaseUrl const baseUrl = apiContext.getState().apiConfig.baseUrl; // 每次调用都创建新的Client实例(或者缓存也可以,这里简单处理) const client = new GraphQLClient(baseUrl); // 调用graphql-request的baseQuery逻辑 return graphqlRequestBaseQuery({ client })(args, apiContext, extraOptions); }, endpoints: () => ({}), });
3. 在测试中设置Mock地址
it('works with rtk', async () => { const pactMockUrl = 'http://localhost:XXXX/graphql'; const reducer = { [api.reducerPath]: api.reducer, apiConfig: apiConfigReducer, // 别忘了把apiConfig reducer加入根reducer }; const { store } = setupStoreAndPersistor({ enableLog: true, rootReducer: reducer, isProduction: false, }); // 先dispatch action设置Mock地址 store.dispatch(setApiBaseUrl(pactMockUrl)); // 发起请求并等待完成 const result = await store.dispatch(api.endpoints.GetModules.initiate()).unwrap(); expect(result).toEqual({modules: []}); });
关键注意点
- 不要用
setTimeout等待请求完成:RTK Query的initiate()返回的是一个Promise,用unwrap()可以直接等待请求成功完成,比固定时间等待可靠得多。 - 原来的问题根源:你之前是把固定的GraphQLClient实例传给baseQuery,RTK Query会缓存这个实例,所以后续修改baseUrl不会生效——必须让baseQuery每次调用都能拿到最新的地址/Client。
内容的提问来源于stack exchange,提问作者mfilimonov
相关产品推荐
相关产品推荐

