无效的挂钩调用。只有在将 useNavigate 和 useEffect 与 axios 拦截器一起使用时,才能在函数组件的主体内部调用钩子

Invalid hook call. Hooks can only be called inside of the body of a function component when using useNavigate and useEffect with axios interceptors

提问人:Văn Thuận Nguyễn 提问时间:11/16/2023 最后编辑:Drew ReeseVăn Thuận Nguyễn 更新时间:11/16/2023 访问量:40

问:

我正在研究 React 并尝试包含用于私有 API 调用的持有者令牌。我写了一个私有 axios 来拦截请求和响应。然后我在 API.js 中调用它以从服务器获取数据。但是,我收到此错误:

错误:挂钩调用无效。钩子只能在身体内部调用 函数组件。以下情况之一可能会发生这种情况 原因:

  1. 你可能有不匹配的 React 和渲染器(例如 React DOM)的版本

  2. 你可能违反了钩子的规则

  3. 你可能在同一个应用中有多个 React 副本

它来自和进来useNavigateuseEffectprivateAxios.js

私人Axios.js

import { axiosPrivate } from "./axios";
import { useEffect } from "react";
// import useRefreshToken from "./useRefreshToken";
import { useNavigate } from "react-router-dom";

const usePrivateAxios = () => {
    const navigate = useNavigate();

    useEffect(() => {
        const requestInterceptor = axiosPrivate.interceptors.request.use(
            (config) => {
                const accessToken = localStorage.getItem("accessToken");

                if (!accessToken) {
                    navigate("/admin/login");
                } else {
                    config.headers.Authorization = `Bearer ${accessToken}`;
                }

                return config;
            },
            (error) => Promise.reject(error),
        );

        const responseInterceptor = axiosPrivate.interceptors.response.use(
            (response) => {
                return response;
            },
            (error) => {
                return Promise.reject(error);
            },
        );

        return () => {
            axiosPrivate.interceptors.request.eject(requestInterceptor);
            axiosPrivate.interceptors.response.eject(responseInterceptor);
        };
    }, [navigate]);
    return axiosPrivate;
};

export default usePrivateAxios;

文档API.js

import privateAxios from "../usePrivateAxios";

export const getAllDocuments = (config) => {
    return privateAxios()
        .get("/documents", config)
        .then((response) => response.data)
        .catch((error) => {
            throw error;
        });
};

我想使用重定向到登录,所以我使用这种方法。useNavigate

javascript reactjs react-hooks axios

评论


答:

1赞 Drew Reese 11/16/2023 #1

usePrivateAxios是一个 React 钩子,所以它必须遵循钩子的规则。在您的代码中,您已将其导入为函数,并在该函数中调用它,该函数既不是 React 函数组件,也不是自定义 React 钩子。privateAxios

由于您只是将请求/响应拦截器注入到 axios 对象中,因此无需使用返回值 from 来发出 GET 请求。 只需在应用中调用一次即可添加拦截器,该函数可以使用 Axios 对象。axiosPrivateusePrivateAxiosusePrivateAxiosgetAllDocumentsprivateAxios

例:

App.jsx(应用程序.jsx)

...
import usePrivateAxios from "../usePrivateAxios";
...

const App = () => {
  // Setup global axios request/response interceptors
  usePrivateAxios();

  ...

  return (
    ...
  );
}
<BrowserRouter>
  <App />
</BrowserRouter>

文档API.js

import { axiosPrivate } from "./axios";

export const getAllDocuments = (config) => {
  return axiosPrivate()
    .get("/documents", config)
    .then((response) => response.data)
    .catch((error) => {
      throw error;
    });
};