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

如何结合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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:01:38