如何在React中实现API返回HTTP 401状态时触发弹窗显示
React中API返回401时触发全局弹窗的实现方案
1. 全局状态管理(用React Context实现)
先通过React Context创建全局状态,统一控制弹窗的显示/隐藏,避免在各个组件中重复维护状态:
// src/contexts/AuthContext.js import { createContext, useContext, useState } from 'react'; const AuthContext = createContext(); export function AuthProvider({ children }) { const [showUnauthorizedModal, setShowUnauthorizedModal] = useState(false); // 触发弹窗的方法 const triggerUnauthorizedModal = () => { setShowUnauthorizedModal(true); }; // 关闭弹窗的方法 const closeUnauthorizedModal = () => { setShowUnauthorizedModal(false); }; return ( <AuthContext.Provider value={{ showUnauthorizedModal, triggerUnauthorizedModal, closeUnauthorizedModal }}> {children} </AuthContext.Provider> ); } // 自定义Hook,方便组件快速调用上下文状态 export function useAuth() { return useContext(AuthContext); }
2. 拦截API请求,捕获401状态码
以axios为例,添加响应拦截器统一处理API返回的401状态:
// src/utils/api.js import axios from 'axios'; import { useAuth } from '../contexts/AuthContext'; // 创建axios实例 const api = axios.create({ baseURL: '你的API基础地址', }); // 初始化拦截器的函数(避免在拦截器中直接使用Hook的问题) export function setupApiInterceptors() { const { triggerUnauthorizedModal } = useAuth(); api.interceptors.response.use( (response) => response, // 请求成功直接返回响应 (error) => { // 检测是否为401未授权状态 if (error.response?.status === 401) { triggerUnauthorizedModal(); } return Promise.reject(error); } ); } export default api;
如果用原生fetch,可以封装统一的请求函数:
// src/utils/fetchWithAuth.js import { useAuth } from '../contexts/AuthContext'; export async function fetchWithAuth(url, options = {}) { const response = await fetch(url, options); const { triggerUnauthorizedModal } = useAuth(); if (response.status === 401) { triggerUnauthorizedModal(); } return response; }
3. 实现401提示弹窗组件
写一个基础弹窗组件,根据全局状态决定是否渲染:
// src/components/UnauthorizedModal.js import { useAuth } from '../contexts/AuthContext'; export default function UnauthorizedModal() { const { showUnauthorizedModal, closeUnauthorizedModal } = useAuth(); if (!showUnauthorizedModal) return null; return ( <div style={{ position: 'fixed', top: 0, left: 0, width: '100%', height: '100%', background: 'rgba(0,0,0,0.5)', display: 'flex', justifyContent: 'center', alignItems: 'center', zIndex: 9999 }}> <div style={{ background: '#fff', padding: '2rem', borderRadius: '8px', boxShadow: '0 3px 12px rgba(0,0,0,0.15)' }}> <h3>登录状态已失效</h3> <p>你的登录权限已过期,请重新登录后操作</p> <button onClick={closeUnauthorizedModal} style={{ marginTop: '1.5rem', padding: '0.6rem 1.2rem', background: '#2563eb', color: '#fff', border: 'none', borderRadius: '4px', cursor: 'pointer' }}> 我知道了 </button> </div> </div> ); }
4. 在App组件中整合所有模块
最后在根组件中挂载Context Provider、初始化拦截器,并渲染弹窗:
// src/App.js import { useEffect } from 'react'; import { AuthProvider, useAuth } from './contexts/AuthContext'; import UnauthorizedModal from './components/UnauthorizedModal'; import { setupApiInterceptors } from './utils/api'; // 导入你的业务页面组件 import Dashboard from './pages/Dashboard'; function AppContent() { useEffect(() => { // 初始化API拦截器 setupApiInterceptors(); }, []); return ( <div className="App"> <Dashboard /> {/* 全局弹窗放在最外层,确保能覆盖所有内容 */} <UnauthorizedModal /> </div> ); } export default function App() { return ( <AuthProvider> <AppContent /> </AuthProvider> ); }
额外说明
- 弹窗样式可以根据项目需求自定义,也可以直接使用Ant Design、Material UI等组件库的Modal组件简化开发;
- 如果需要在弹窗中添加"跳转登录页"逻辑,只需在弹窗按钮的点击事件中添加路由跳转代码即可。
内容的提问来源于stack exchange,提问作者mc9724
相关产品推荐
相关产品推荐

