RTK查询拦截器循环依赖
Posted
技术标签:
【中文标题】RTK查询拦截器循环依赖【英文标题】:RTK Query Interceptor Circular Dependency 【发布时间】:2022-01-13 15:55:53 【问题描述】:试图找出实现以下目标的最佳方法:
-
API 通过
createApi
通过createSlice
验证切片
API 收到 401 时清除 redux 身份验证状态。
前两个没问题!但问题是当我需要向 API 添加拦截器时(无效的身份验证 - 清除本地身份验证状态):
// api.ts
import authSlice from './authSlice';
const baseQueryWithReauth: BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError> = async (
args,
api,
extraOptions
) =>
const result = await baseQuery(args, api, extraOptions)
if (result.error?.status === 401)
api.dispatch(authSlice.actions.clearAuth())
return result
export const api = createApi(
reducerPath: API_REDUCER_KEY,
baseQuery: baseQueryWithReauth,
endpoints: () => (),
)
// authService.ts
import User from '../../models/User'
import api from '../api'
export const API_REDUCER_KEY = 'api'
interface AuthResponse
user: User
jwt: string
interface LoginData
email: string
password: string
export const authApi = api.injectEndpoints(
endpoints: (builder) => (
login: builder.mutation<AuthResponse, LoginData>(
query: (body) =>
return
url: 'login',
method: 'POST',
body,
,
),
),
)
export const useLoginMutation = authApi
这会导致循环依赖 - 因为身份验证切片需要为身份验证功能(登录、注销等)调用 API:
// authSlice.ts
import api from './api';
...
export const loginLocal = createAsyncThunk<
Pick<AuthState, 'user' | 'accessToken'>,
email: string
password: string
>('auth/login', async ( email, password , dispatch ) =>
const response = await dispatch(
authApi.endpoints.login.initiate(
email,
password,
)
)
if ('error' in response)
if ('status' in response.error)
throw new Error(response.error.data as string)
throw new Error(response.error.message)
const data = response
const jwt: accessToken, user = data
return user, accessToken
)
循环依赖如下:authSlice -> authService -> api -> authSlice
有没有办法解决这个问题 - 或者我可以使用更好/不同的模式?
【问题讨论】:
如果你把baseQueryWithReauth
移到一个单独的文件里会不会解决问题?比你不必在你的api.ts
中导入authSlice
另外,为什么loginLocal
写成createAsyncThunk
?这感觉就像会进入 API 切片一样。
@TheWuif - 我相信这仍然是一个循环依赖,只是在链中有一个额外的链接:authSlice -> authService -> api -> baseQueryWithReauth -> authSlice
@markerikson - 我也在该函数中应用一些与问题无关的异步逻辑:)
【参考方案1】:
一个简单的解决方案是简单地将“clearAuth”操作拉到它自己的文件中 - 按照https://redux-toolkit.js.org/usage/usage-guide#exporting-and-using-slices:
这通常需要将共享代码提取到两个模块都可以导入和使用的单独公共文件中。在这种情况下,您可以使用 createAction 在单独的文件中定义一些常见的动作类型,将这些动作创建者导入每个切片文件,并使用 extraReducers 参数处理它们。
// clearAuthAction.ts
import createAction from '@reduxjs/toolkit'
export const CLEAR_AUTH = 'auth/clearAuth'
export const clearAuth = createAction<void>(CLEAR_AUTH)
然后在authSlice中使用builder:
// authSlice.ts
builder.addCase(CLEAR_AUTH, (state) =>
state.user = null
state.accessToken = null
)
并在 API 中调度 clearAuth:
// api.ts
const baseQueryWithReauth: BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError> = async (
args,
api,
extraOptions
) =>
const result = await baseQuery(args, api, extraOptions)
if (result.error?.status === 401 || result.error?.status === 403)
api.dispatch(clearAuth())
return result
【讨论】:
以上是关于RTK查询拦截器循环依赖的主要内容,如果未能解决你的问题,请参考以下文章
将 $state (ui-router) 注入 $http 拦截器会导致循环依赖