RTK Query中间件内无法调用接口,求登录后获用户信息替代方案
解决方案:RTK Query登录后单次调用/me接口的替代方案
你之前的中间件报错核心原因是:React钩子(useDispatch、useLazyQuery)只能在React函数组件或自定义钩子的顶层执行,而Redux中间件属于独立于React组件树的底层逻辑,没有React上下文支持,直接调用钩子必然触发错误。
下面提供几种可行的替代方案,避开空组件和错误的中间件写法:
方案1:修正Listener Middleware的正确写法
不需要依赖React钩子,直接利用Listener Middleware自带的listenerApi获取dispatch,调用RTK Query的initiate方法触发查询(initiate会直接生成可被dispatch的查询action):
import { createListenerMiddleware } from "@reduxjs/toolkit"; import { ACTION_SET_ACCESS_TOKEN } from "../utils/constants/constant"; import { apiSlice } from "../features/apiSlice"; const type = `accessTokenSlice/${ACTION_SET_ACCESS_TOKEN}`; const meMiddleware = createListenerMiddleware(); meMiddleware.startListening({ type, effect: async (_, listenerApi) => { // 使用listenerApi内置的dispatch,无需useDispatch钩子 await listenerApi.dispatch( apiSlice.endpoints.getMe.initiate(undefined, { forceRefetch: true }) ); } }); export default meMiddleware;
方案2:在登录成功逻辑中直接触发查询
既然是登录后才需要调用/me接口,最直接的方式是在登录流程的收尾阶段(比如拿到accessToken后)直接dispatch查询动作:
比如在登录异步thunk中:
import { createAsyncThunk } from "@reduxjs/toolkit"; import { apiSlice } from "../features/apiSlice"; import { accessTokenSlice } from "../features/accessTokenSlice"; export const login = createAsyncThunk( 'auth/login', async (credentials, { dispatch }) => { // 调用登录接口获取token const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credentials) }); const loginResult = await response.json(); // 设置accessToken dispatch(accessTokenSlice.actions.setAccessToken(loginResult.token)); // 直接触发/me接口查询 dispatch(apiSlice.endpoints.getMe.initiate(undefined)); return loginResult; } );
方案3:用useGetMeQuery配合skip条件替代空组件
无需编写专门返回null的组件,在App或顶层布局组件中使用useGetMeQuery,通过skip参数控制查询时机:
import { useGetMeQuery } from "../features/apiSlice"; import { useSelector } from "react-redux"; function App() { const accessToken = useSelector(state => state.accessTokenSlice.accessToken); // 从RTK Query的缓存中读取已有的用户数据 const existingUserData = useSelector( state => state[apiSlice.reducerPath].queries.getMe?.data ); // 只有当存在accessToken且无用户数据时,才执行查询;否则跳过 const { data: userData } = useGetMeQuery(undefined, { skip: !accessToken || !!existingUserData, refetchOnMountOrArgChange: false, // 确保仅执行一次查询 refetchOnReconnect: false }); // 正常渲染应用内容即可 return ( <div className="app-container"> {/* 你的应用组件 */} </div> ); }
内容的提问来源于stack exchange,提问作者sineverba
相关产品推荐
相关产品推荐

