如何结合Redux-Toolkit与RTK Query实现登录API调用?
问题描述
项目中同时使用Redux-Toolkit(RTK)和RTK Query,希望在auth切片中实现登录API调用,且调用时使用已预定义好的、基于fetchBaseQuery封装的baseQuery。尝试在createAsyncThunk中调用RTK Query的useLoginMutation但无法正常工作,寻求可行实现方案,若当前思路不可行,也请提供合适的后端连接实现方式。
预定义的baseQuery
export const baseQuery = retry(fetchBaseQuery({ timeout: 5000, headers: { 'Content-Type': 'application/json;charset=utf-8', 'Access-Control-Allow-Origin': '*', }, prepareHeaders: (headers, { getState }) => { const accessToken = localStorage.getItem(AUTH_TOKEN_KEY) || ''; const uid = getLocal(UID_KEY); if (accessToken) { headers.set('Authorization', accessToken); headers.set(UID_KEY, uid); } return headers; }, }), { maxRetries: 3 });
尝试的createAsyncThunk代码
export const loginAsync = createAsyncThunk( 'auth/login', async (credentials: LoginValuesType, thunkAPI) => { try { // How to call the mutation here? // const response = await userApi.useLoginMutation(credentials) if (response?.data?.code === 0) { localStorage.setItem(AUTH_TOKEN_KEY, response.data?.data?.token); setLocal('uid', response.data?.data?.uid); return response.data; } else if (response?.data?.code === 1) { thunkAPI.dispatch(showError(response?.data?.msg)) return thunkAPI.rejectWithValue({msg: response?.data?.msg}) } } catch (e) { thunkAPI.dispatch(showError('An error occurred')) return thunkAPI.rejectWithValue({msg: "An error occurred"}) } } )
已实现的RTK Query mutation代码
export const userApi = createApi({ reducerPath: 'userApi', baseQuery: baseQuery, endpoints: (builder) => ({ login: builder.mutation({ query: (args) => { return { url: '/api/v1/sign_in', method: 'POST', body: args, } }, }), }), }); export const { useLoginMutation } = userApi;
可行实现方案
方案一:直接使用RTK Query Mutation + Redux切片同步状态
RTK Query的useLoginMutation是React Hook,仅能在组件或自定义Hook中调用,无法在createAsyncThunk这类非Hook环境使用。正确做法是在组件中调用mutation,通过RTK Query的onQueryStarted钩子处理登录后的状态同步:
1. 改造RTK Query的login mutation
在userApi的login mutation中添加onQueryStarted,处理登录成功后的token存储和redux状态更新:
export const userApi = createApi({ reducerPath: 'userApi', baseQuery: baseQuery, endpoints: (builder) => ({ login: builder.mutation({ query: (args) => ({ url: '/api/v1/sign_in', method: 'POST', body: args, }), async onQueryStarted(args, { dispatch, queryFulfilled }) { try { const { data } = await queryFulfilled; if (data.code === 0) { // 存储token与uid localStorage.setItem(AUTH_TOKEN_KEY, data.data.token); setLocal('uid', data.data.uid); // 触发auth切片的登录成功action dispatch(authSlice.actions.loginSuccess(data.data)); } else if (data.code === 1) { dispatch(showError(data.msg)); } } catch (error) { dispatch(showError('An error occurred')); } }, }), }), }); export const { useLoginMutation } = userApi;
2. 在组件中调用mutation
import { useLoginMutation } from './userApi'; function LoginComponent() { const [login, { isLoading }] = useLoginMutation(); const handleLogin = async (credentials) => { try { await login(credentials).unwrap(); // 登录成功后的后续逻辑,如页面跳转 } catch (error) { // 处理mutation抛出的错误 } }; return ( // 登录表单渲染逻辑 ); }
方案二:在createAsyncThunk中直接调用baseQuery
如果必须在createAsyncThunk中实现登录逻辑,可以直接调用预定义的baseQuery,无需依赖RTK Query的mutation:
export const loginAsync = createAsyncThunk( 'auth/login', async (credentials: LoginValuesType, thunkAPI) => { try { // 直接调用baseQuery,传入请求配置 const response = await baseQuery( { url: '/api/v1/sign_in', method: 'POST', body: credentials, }, thunkAPI.getState(), {} // baseQuery额外配置,可留空 ); // baseQuery返回结构为{ data }或{ error },需判断处理 if ('data' in response) { const data = response.data; if (data.code === 0) { localStorage.setItem(AUTH_TOKEN_KEY, data.data.token); setLocal('uid', data.data.uid); return data; } else if (data.code === 1) { thunkAPI.dispatch(showError(data.msg)); return thunkAPI.rejectWithValue({ msg: data.msg }); } } else { thunkAPI.dispatch(showError('An error occurred')); return thunkAPI.rejectWithValue({ msg: 'An error occurred' }); } } catch (e) { thunkAPI.dispatch(showError('An error occurred')); return thunkAPI.rejectWithValue({ msg: 'An error occurred' }); } } );
注意事项
baseQuery调用参数为(请求配置, redux状态, 额外选项),请求配置结构与RTK Query mutation的query返回值一致。baseQuery返回Promise,解析后为{ data: TData }或{ error: FetchBaseQueryError },需判断类型处理结果。
内容的提问来源于stack exchange,提问作者Awantha Irushan
相关产品推荐
相关产品推荐

