如何在RTK Query的API定义文件中获取Redux-Persist持久化的accessToken
解决方案
1. 让baseQuery动态获取token
RTK Query的fetchBaseQuery支持在请求时动态从store读取状态,无需在API定义阶段就传入固定token。你可以借助baseQuery的第二个参数api,它包含getState方法,能实时获取store中已持久化的accessToken。
示例代码:
import { fetchBaseQuery } from '@reduxjs/toolkit/query/react'; const baseQuery = fetchBaseQuery({ baseUrl: '/api', prepareHeaders: (headers, { getState }) => { // 从store中读取最新的持久化token const token = getState().auth.accessToken; if (token) { headers.set('Authorization', `Bearer ${token}`); } return headers; }, });
每次发起API请求时,都会自动从store中取当前有效的token,包括persist完成hydrate后的token。
2. 拦截Hydrate完成前的请求
页面加载时,如果组件在persist完成状态恢复前就发起请求,会因token未就绪导致失败,可通过以下两种方式处理:
方式一:在store中追踪hydrate状态
在自定义slice中添加hydrated状态,监听redux-persist的HYDRATE action:
import { createSlice } from '@reduxjs/toolkit'; import { PURGE, REGISTER, REHYDRATE } from 'redux-persist'; const appSlice = createSlice({ name: 'app', initialState: { hydrated: false, }, reducers: {}, extraReducers: (builder) => { builder .addCase(REHYDRATE, (state) => { state.hydrated = true; }) .addCase(PURGE, (state) => { state.hydrated = false; }) .addCase(REGISTER, (state) => { state.hydrated = true; }); }, }); export default appSlice.reducer;
然后在组件中,等待hydrated为true后再触发API请求:
import { useSelector } from 'react-redux'; import { useGetDataQuery } from './api'; function MyComponent() { const isHydrated = useSelector(state => state.app.hydrated); const { data, error, isLoading } = useGetDataQuery(undefined, { skip: !isHydrated, // 未完成hydrate时跳过请求 }); if (!isHydrated) { return <div>加载中...</div>; } // 渲染业务数据 }
方式二:在baseQuery中等待hydrate完成
封装自定义baseQuery,确保请求发送前store已完成状态恢复:
import { fetchBaseQuery } from '@reduxjs/toolkit/query/react'; import { store } from './store'; const baseQuery = fetchBaseQuery({ baseUrl: '/api', prepareHeaders: (headers, { getState }) => { const token = getState().auth.accessToken; if (token) { headers.set('Authorization', `Bearer ${token}`); } return headers; }, }); const hydratedBaseQuery = async (args, api, extraOptions) => { // 轮询等待hydrate完成 while (!store.getState().app.hydrated) { await new Promise(resolve => setTimeout(resolve, 50)); } return baseQuery(args, api, extraOptions); }; // 定义API时使用封装后的baseQuery export const api = createApi({ baseQuery: hydratedBaseQuery, endpoints: (builder) => ({ // 你的API端点定义 }), });
3. 确保RTK Query与Redux-Persist兼容
配置store时,将RTK Query的reducer加入persist黑名单(无需持久化API缓存),同时关闭serializableCheck对persist相关action的校验:
import { persistStore, persistReducer } from 'redux-persist'; import storage from 'redux-persist/lib/storage'; import { combineReducers, configureStore } from '@reduxjs/toolkit'; import { FLUSH, PAUSE, PERSIST, PURGE, REGISTER, REHYDRATE } from 'redux-persist'; import { api } from './api'; import authReducer from './authSlice'; import appReducer from './appSlice'; const persistConfig = { key: 'root', storage, blacklist: [api.reducerPath], // 不持久化RTK Query缓存 }; const rootReducer = combineReducers({ [api.reducerPath]: api.reducer, auth: authReducer, app: appReducer, }); const persistedReducer = persistReducer(persistConfig, rootReducer); export const store = configureStore({ reducer: persistedReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: { ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], }, }).concat(api.middleware), }); export const persistor = persistStore(store);
内容的提问来源于stack exchange,提问作者Abdul Aziz
相关产品推荐
相关产品推荐

