React Query中queryClient mutations的onError回调无法弹出Toast
Next.js + React-Query 全局Toast不弹出问题解决
核心问题原因
问题出在React Hook的闭包陷阱:useApiError返回的handleApiError里,showToast是组件初始化时捕获的上下文版本,但你通过useState的初始化函数创建QueryClient,这个函数只会执行一次,导致后续mutation触发错误时,handleApiError里的showToast并没有绑定到最新的React上下文,无法触发Toast渲染(但console.log不受上下文影响,所以能正常打印)。
具体修复方案
方案1:用useEffect同步最新的错误处理函数
把QueryClient的创建和配置拆分,用useEffect在组件更新时同步最新的handleApiError,确保每次错误回调都能拿到有效的showToast:
const handleApiError = useApiError(); // 先创建基础的QueryClient const [queryClient] = React.useState(() => new QueryClient()); React.useEffect(() => { // 每次handleApiError更新时,重新设置默认配置 queryClient.setDefaultOptions({ queries: { retry: 0, refetchOnWindowFocus: false, throwOnError: true, staleTime: 5 * 1000, }, mutations: { retry: 0, onError: handleApiError, }, }); }, [handleApiError, queryClient]);
方案2:在单个mutation中手动传入onError
放弃全局配置,在每个mutation创建时直接传入最新的handleApiError,绕开闭包问题:
const handleApiError = useApiError(); // 示例mutation const submitFormMutation = useMutation({ mutationFn: (data) => yourApiService.submit(data), onError: handleApiError, // 其他mutation配置 });
方案3:用React-Query全局错误边界捕获
利用React-Query提供的错误边界能力,全局捕获所有query/mutation错误后触发Toast,这种方式更符合React的错误处理逻辑:
// 自定义全局错误边界组件 export function QueryErrorBoundary({ children }) { const { showToast } = useToast(); const { error, reset } = useQueryErrorResetBoundary(); React.useEffect(() => { if (error) { const message = ApiError.parsedErrorMessage(error as AxiosError) ?? TOAST_MESSAGE.fail; showToast({ type: 'fail', message }); // 重置错误状态,避免重复触发 reset(); } }, [error, reset, showToast]); return children; } // 在_app.tsx中包裹根组件 function MyApp({ Component, pageProps }) { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: 0, refetchOnWindowFocus: false, throwOnError: true, staleTime: 5 * 1000, }, mutations: { retry: 0, }, }, }); return ( <QueryClientProvider client={queryClient}> <QueryErrorBoundary> <Component {...pageProps} /> </QueryErrorBoundary> </QueryClientProvider> ); }
关键注意事项
- 不要在
useState的初始化函数中依赖外部Hook的返回值,因为这个函数只会执行一次,无法响应后续的上下文或状态变化。 - 如果坚持用全局配置,必须确保配置能同步最新的Hook值,
useEffect是最可靠的方式。
内容的提问来源于stack exchange,提问作者2ne1
相关产品推荐
相关产品推荐

