如何在Service类中使用enqueueSnackbar?解决React Hook调用错误
解决Service中使用enqueueSnackbar的问题
你遇到的错误核心原因是:React Hook必须在React函数组件或自定义Hook内部调用,Service文件属于普通JS模块,并非组件或Hook范畴,所以直接在里面调用useSnackbar会触发规则校验报错。下面给你三种可行的解决方式:
方法一:将enqueueSnackbar作为参数传入Service方法
这种方式最直接,让Service方法从调用它的组件处接收提示函数,完全不依赖React Hook:
修改service.js:
import axios from "./axios"; export const postWithoutAuth = (url, body, enqueueSnackbar) => { return axios.post(url, body) .then((response) => response.data) .catch((error) => { // 调用传入的提示函数展示错误 enqueueSnackbar(error.response.data.message, { variant: "error" }); // 抛出错误,方便组件层面做额外处理(可选) throw error; }); };
修改Login.tsx的handleSubmit:
const handleSubmit = (event) => { // ... postWithoutAuth(loginUrl, formData, enqueueSnackbar) .then((data) => { // 处理登录成功逻辑 }) // 若需要组件层面额外处理错误,可保留此catch .catch((error) => { /* 可选的额外逻辑 */ }); };
方法二:全局注册Snackbar实例
利用notistack的SnackbarProvider的ref,创建一个全局可调用的提示方法:
在App.js(或根组件)中设置全局ref:
import { SnackbarProvider, useSnackbar } from "notistack"; import React, { createRef, useImperativeHandle, forwardRef } from "react"; // 创建全局ref用于存储Snackbar实例 const snackbarRef = createRef(); // 包装SnackbarProvider,暴露enqueueSnackbar方法 const SnackbarProviderWrapper = forwardRef((props, ref) => { const { enqueueSnackbar } = useSnackbar(); useImperativeHandle(ref, () => ({ enqueueSnackbar })); return <SnackbarProvider {...props} />; }); // 根组件渲染逻辑 function App() { return ( <SnackbarProviderWrapper ref={snackbarRef}> {/* 其他业务组件 */} </SnackbarProviderWrapper> ); } // 导出全局ref供Service调用 export { snackbarRef };
修改service.js:
import axios from "./axios"; import { snackbarRef } from "./App"; export const postWithoutAuth = (url, body) => { return axios.post(url, body) .then((response) => response.data) .catch((error) => { // 通过全局ref调用提示方法 snackbarRef.current?.enqueueSnackbar(error.response.data.message, { variant: "error" }); throw error; }); };
方法三:用自定义Hook封装Service逻辑
把请求逻辑放到自定义Hook里,这样就能合法使用useSnackbar:
创建useApi.js自定义Hook:
import { useSnackbar } from "notistack"; import axios from "./axios"; export const useApi = () => { const { enqueueSnackbar } = useSnackbar(); const postWithoutAuth = (url, body) => { return axios.post(url, body) .then((response) => response.data) .catch((error) => { enqueueSnackbar(error.response.data.message, { variant: "error" }); throw error; }); }; return { postWithoutAuth }; };
在Login.tsx中使用:
import { useApi } from "./useApi"; // ... const Login = () => { const { postWithoutAuth } = useApi(); const handleSubmit = (event) => { // ... postWithoutAuth(loginUrl, formData) .then((data) => { // 处理登录成功逻辑 }); }; };
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

