尽管在功能组件内使用了钩子,但 Hook 调用仍然无效

问题描述 投票:0回答:1

嗨,这是 Axios 的下一个 js 应用程序,TanstackQuery。我正在尝试重新路由到“/login”页面,以防 AxiosInterCeptorIntance 捕获 401。 React 版本 18、react-dom 版本 18、React 14.1.3

使用

useRouter
next/navigation

会引发错误
import axios from "axios";
import { RedirectType, redirect, useRouter } from "next/navigation";
import toast from "react-hot-toast";

const AxiosInterceptorInstance = () => {
  const router = useRouter();

  const axiosInterceptorInstance = axios.create({
    baseURL: process.env.NEXT_PUBLIC_API_URL,
  });

  // Request interceptor
  axiosInterceptorInstance.interceptors.request.use(
    (config) => {
      const accessToken = localStorage.getItem("auth_token");
      if (accessToken) {
        if (config.headers)
          config.headers.Authorization = `Bearer ${accessToken}`;
      }
      return config;
    },
    (error) => {
      return Promise.reject(error);
    },
  );

  // Response interceptor
  axiosInterceptorInstance.interceptors.response.use(
    (response) => {
      return response;
    },
    (error) => {
      switch (error.response.status) {
        case 401:
          toast.error(`${error.response.data.message}`, {
            duration: 4500,
          });
          router.push("/login");
          break;

        case 422:
          toast.error(`${error.response.data.errors[0]}`, {
            duration: 2500,
          });
          break;

        case 500:
          toast.error("something went wrong", {
            duration: 2500,
          });
          break;

        default:
          toast.error(`${error.response.statusText} | ${error.message}`);
          break;
      }
      return Promise.reject(error);
    },
  );

  return { axiosInterceptorInstance };
};

export default AxiosInterceptorInstance;

  • 尝试了下一个js的
    redirect
    ,没有出现语法错误,但也没有重新路由
  • 尝试过
    window.location = "/login"
    ,陷入无限循环enter image description here
reactjs next.js axios
1个回答
0
投票

您不能在 React hooks 或 React 组件之外使用 hooks。

您可以使用事件总线来发出路由器,例如:

// event-bus.ts
import type { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';

import eventemitter from 'eventemitter3';

export const eventBus = eventemitter();

export const push = (path: string) => {
  eventBus.emit('router-push', path);
}

export const subscribe = (router: AppRouterInstance) => {
   const onPush = (path: string) => {
      router.push(path);
    }
    eventBus.on('router-push', onPush);
    return () => {
      eventBus.off('router-push', onPush);
    }
}
'use client'
 
// Create SetupRouterListener.tsx 
// Then add this component to your Layout.tsx

import { useRouter } from 'next/navigation'
import { useEffect } from 'react'
import { eventBus, subscribe } from './event-bus';

export default function SetupRouterListener() {
  const router = useRouter();
  useEffect(() => {
    return subscribe(router);
  }, [router]);

  return null
}

终于有了一些改进:

import axios from "axios";
import toast from "react-hot-toast";
import { push } from './event-bus';

const isBrowser = typeof document !== 'undefined';

const AxiosInterceptorInstance = () => {

  const axiosInterceptorInstance = axios.create({
    baseURL: process.env.NEXT_PUBLIC_API_URL,
  });

  // Request interceptor
  axiosInterceptorInstance.interceptors.request.use(
    (config) => {
      const accessToken = isBrowser ? localStorage.getItem("auth_token") : '';
      if (accessToken) {
        if (config.headers)
          config.headers.Authorization = `Bearer ${accessToken}`;
      }
      return config;
    },
    (error) => {
      return Promise.reject(error);
    },
  );

  // Response interceptor
  axiosInterceptorInstance.interceptors.response.use(
    (response) => {
      return response;
    },
    (error) => {
      switch (error.response.status) {
        case 401:
          toast.error(`${error.response.data.message}`, {
            duration: 4500,
          });
          push("/login");
          break;

        case 422:
          toast.error(`${error.response.data.errors[0]}`, {
            duration: 2500,
          });
          break;

        case 500:
          toast.error("something went wrong", {
            duration: 2500,
          });
          break;

        default:
          toast.error(`${error.response.statusText} | ${error.message}`);
          break;
      }
      return Promise.reject(error);
    },
  );

  return { axiosInterceptorInstance };
};

export default AxiosInterceptorInstance;
© www.soinside.com 2019 - 2024. All rights reserved.