You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 01:45:25