如何在React Context中更新API错误及处理useEffect依赖
全局API错误处理方案(React Context + Axios拦截器)
一、核心问题分析
你最初的代码失效是因为React Hook(如useContext)只能在React组件或自定义Hook内部调用,而Axios拦截器的初始化代码不在组件生命周期内,所以无法直接使用useContext更新上下文状态。
二、完整实现步骤
1. 正确配置错误上下文(Context)
首先需要用useState管理错误状态,确保上下文提供可更新的状态和方法:
import { createContext, useState, useContext } from 'react'; // 创建错误上下文 const APIErrorContext = createContext({ error: '', setError: () => {}, }); // 自定义Hook简化上下文调用 export const useAPIError = () => useContext(APIErrorContext); // 上下文提供者组件 export const APIErrorProvider = ({ children }) => { const [error, setError] = useState(''); return ( <APIErrorContext.Provider value={{ error, setError }}> {children} </APIErrorContext.Provider> ); };
2. 实现Axios错误拦截器组件
将拦截器的初始化逻辑放到React组件内部的useEffect中,这样就能合法调用useContext:
import { useEffect } from 'react'; import axios from 'axios'; import { useAPIError } from './APIErrorContext'; const AxiosErrorHandler = ({ children }) => { const { setError } = useAPIError(); useEffect(() => { // 注册响应拦截器 const responseInterceptor = axios.interceptors.response.use( (response) => response, // 正常响应直接返回 (error) => { // 安全提取错误信息(兼容无响应的网络错误) const errorMsg = error.response?.data?.message || error.message || '未知错误'; setError(errorMsg); // 继续抛出错误,允许单个请求自行处理 return Promise.reject(error); } ); // 组件卸载时移除拦截器,避免内存泄漏 return () => { axios.interceptors.response.eject(responseInterceptor); }; }, [setError]); // 依赖项传入setError,遵循React Hook规则(setError来自useState,稳定不会频繁变化) return children; }; export default AxiosErrorHandler;
3. 整合到App组件中
在根组件中嵌套上下文提供者和错误拦截器组件:
import { APIErrorProvider } from './APIErrorContext'; import AxiosErrorHandler from './AxiosErrorHandler'; import ChildComponent from './ChildComponent'; import ErrorModal from './ErrorModal'; const App = () => { return ( <APIErrorProvider> <AxiosErrorHandler> <ChildComponent /> <ErrorModal /> {/* 全局错误弹窗组件 */} </AxiosErrorHandler> </APIErrorProvider> ); }; export default App;
4. 实现全局错误弹窗组件
订阅上下文状态,自动展示错误信息:
import { useAPIError } from './APIErrorContext'; const ErrorModal = () => { const { error, setError } = useAPIError(); if (!error) return null; return ( <div style={{ position: 'fixed', top: 0, left: 0, right: 0, padding: '1rem', background: '#ff4444', color: 'white' }}> <p>{error}</p> <button onClick={() => setError('')} style={{ marginLeft: '1rem' }}>关闭</button> </div> ); }; export default ErrorModal;
三、关于useEffect依赖项的说明
useEffect的依赖数组需要传入setError,原因如下:
- 虽然
useState返回的setError是稳定函数(不会随组件渲染变化),但遵循React Hook规则,必须将所有在effect内部使用的外部变量加入依赖数组 - 这样可以避免ESLint警告,同时保证逻辑的严谨性
内容的提问来源于stack exchange,提问作者kishore.jannarapu
相关产品推荐
相关产品推荐

