如何用Redux Toolkit的createMiddlewareListener实现页面登录前置校验?
用Redux Toolkit的Listener Middleware实现页面登录校验
首先纠正一点:Redux Toolkit里并没有createMiddlewareListener这个API,你需要用的是**createListenerMiddleware**(属于@reduxjs/toolkit的listener middleware功能),用来监听特定动作(比如路由跳转)并执行登录校验逻辑。以下是具体实现步骤:
步骤1:创建Listener Middleware并定义校验逻辑
新建一个文件(比如authListener.js),创建listener实例并监听路由跳转动作,触发登录状态校验:
import { createListenerMiddleware } from '@reduxjs/toolkit'; import { loginApi } from './你的loginApi路径'; import TokenUtil from './你的TokenUtil路径'; // 如果你用react-router,导入路由变化的action(需配合react-router-redux或自定义导航action) import { LOCATION_CHANGE } from 'react-router-redux'; // 创建listener middleware实例 export const authListenerMiddleware = createListenerMiddleware(); // 添加登录校验监听器 authListenerMiddleware.startListening({ // 监听路由跳转动作 actionCreator: LOCATION_CHANGE, // 过滤需要校验的页面:排除登录页,其他页面都触发校验 predicate: (action) => { const { pathname } = action.payload.location; return pathname !== '/login'; }, async effect(action, listenerApi) { // 先检查本地是否存在token const token = TokenUtil.getToken(); if (!token) { window.location.href = '/login'; return; } try { // 调用getMe接口校验token有效性 const result = await listenerApi.dispatch(loginApi.endpoints.getMe.initiate()); if (result.isError) { // token无效则清除并跳转登录页 TokenUtil.clearToken(); window.location.href = '/login'; } // 校验通过则正常访问页面 } catch (error) { console.error('登录校验失败:', error); TokenUtil.clearToken(); window.location.href = '/login'; } }, });
步骤2:优化API的Token获取方式
你当前的getMe接口直接硬编码token获取逻辑,建议改用fetchBaseQuery的prepareHeaders动态设置,确保token更新时能自动同步:
export const loginApi = createApi({ reducerPath: "loginApi", tagTypes: ["Login"], baseQuery: fetchBaseQuery({ baseUrl: appConfig.apiUrl, jsonContentType: "application/json", // 动态设置请求头 prepareHeaders: (headers) => { const token = TokenUtil.getToken(); if (token) { headers.set('Authorization', `Bearer ${token}`); } return headers; } }), endpoints: (build) => ({ login: build.mutation({ query: ({ username, password }) => ({ url: "/auth/login", method: "POST", body: { username, password }, }), // 登录成功后自动保存token到本地 async onQueryStarted(args, { queryFulfilled }) { try { const { data } = await queryFulfilled; TokenUtil.setToken(data.token); // 假设接口返回token字段 } catch (error) { console.error('登录失败:', error); } } }), getMe: build.query({ query: () => "/auth/me", // 无需手动设置headers,prepareHeaders会自动处理 }), }), }); export const { useLoginMutation, useGetMeQuery } = loginApi;
步骤3:将Listener Middleware加入Store配置
修改你的configureStore代码,把authListenerMiddleware加入到中间件数组中:
import { configureStore } from '@reduxjs/toolkit'; import { loginApi } from './你的loginApi路径'; import { authListenerMiddleware } from './你的authListener路径'; export const store = configureStore({ reducer: { [loginApi.reducerPath]: loginApi.reducer, //...其他reducers }, middleware: (getDefaultMiddleware) => getDefaultMiddleware() .concat(loginApi.middleware) .prepend(authListenerMiddleware.middleware), // prepend确保校验逻辑优先执行 });
补充说明
- 如果你没有使用
react-router-redux,可以在页面组件的useEffect中触发自定义action(比如dispatch({ type: 'page/load', payload: { pathname } })),然后在listener中监听该action。 - 可根据业务需求调整
predicate逻辑,过滤不需要校验的公开页面。
内容的提问来源于stack exchange,提问作者Dharma Fattahul Winzi
相关产品推荐
相关产品推荐

