如何在Redux Toolkit的createApi外部使用baseQuery
问题描述
为缩减应用体积,需要移除Redux Toolkit异步thunk中的axios依赖,复用已配置应用全局请求头的baseQuery函数。
原有基于axios的登录thunk实现如下:
export const loginAsyncThunk = createAsyncThunk<loginResponse, loginArgs>( 'session/login', ({ username, password }) => new Promise((resolve, reject) => { axios.post( ROUTES.LOGIN(), { email: username, password } ) .then((response) => resolve(response.data)) .catch((error: AxiosError | typeof Error) => { if (axios.isAxiosError(error)) { reject(error.response?.data) } reject(error) }) }) )
尝试基于fetchBaseQuery改写时,调用baseQuery传入第二、第三个参数为undefined,控制台抛出错误:TypeError: Cannot read property 'signal' of undefined,不清楚baseQuery要求的api、extraOptions参数如何正确配置。
报错时的错误实现:
export const baseQuery = fetchBaseQuery({ baseUrl: ROUTES.API_HOST, prepareHeaders: (headers, api) => { // app global headers headers.set('Content-Type', `application/json`) return headers }, }) export const loginAsyncThunk = createAsyncThunk<loginResponse, loginArgs>( 'session/login', ({ username, password }) => new Promise((resolve, reject) => { const calledBaseQuery = baseQuery({ url: ROUTES.LOGIN(), body: { email: username, password }, // @ts-ignore: What should I do with following "api" and "extraOptions"? }, undefined, undefined) console.log(calledBaseQuery) // Promise {<rejected>: TypeError: Cannot read property 'signal' of undefined} }) )
报错原因
fetchBaseQuery返回的baseQuery不是独立可用的通用请求函数,它强依赖上下文参数:
- 第二个位置的
api参数是thunk执行上下文,必须包含signal(请求中断信号)、dispatch、getState等必填属性,传undefined会直接导致内部读取signal属性时报错 - 第三个位置的
extraOptions是自定义扩展配置项,无特殊需求不能传undefined,需传空对象占位
正确实现
createAsyncThunk的payload回调第二个参数会自动注入完整的thunkAPI对象,直接把这个对象传给baseQuery即可,不需要手动构造,也不需要额外包裹Promise层。
修正后的代码:
export const baseQuery = fetchBaseQuery({ baseUrl: ROUTES.API_HOST, prepareHeaders: (headers) => { // 保留原有全局请求头配置逻辑 headers.set('Content-Type', 'application/json') return headers }, }) export const loginAsyncThunk = createAsyncThunk<loginResponse, loginArgs>( 'session/login', async ({ username, password }, thunkAPI) => { const requestResult = await baseQuery( { url: ROUTES.LOGIN(), method: 'POST', // 显式指定POST方法,baseQuery默认发GET请求 body: { email: username, password }, }, thunkAPI, // 直接传入thunk注入的上下文,包含所有baseQuery需要的字段 {} // 无额外自定义配置时传空对象即可 ) // 对齐原有axios版本的错误、成功返回逻辑 if (requestResult.error) { return thunkAPI.rejectWithValue(requestResult.error.data) } return requestResult.data as loginResponse } )
关键注意点
- 不要手动构造api参数对象,直接复用
createAsyncThunk注入的thunkAPI即可,避免漏传属性导致报错 - baseQuery默认请求方法为GET,涉及POST/PUT/DELETE等请求必须显式声明method字段
- 不需要手动套
new Promise包装,baseQuery本身返回Promise,直接用async/await写法更简洁,也能避免手写Promise带来的resolve/reject遗漏问题 - baseQuery返回结果是固定的二元结构:成功时返回
{ data: 接口返回值 },失败时返回{ error: 错误对象 },需要手动判断分支处理结果
内容的提问来源于stack exchange,提问作者Rashomon
相关产品推荐
相关产品推荐

