You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 14:27:29