Next.JS 中止获取路由组件:“/login”

김정수*_*김정수 18 authentication next.js next-router

我正在开发一个用于每页身份验证的 useUser Hook。我已经正常实现了 useUser 挂钩,因此重定向工作正常。但我收到上述错误。

中止获取路由组件:“/login”

我该如何修复 useUserHook 来解​​决它?

//useUser.tsx
const useUser = ({ redirectTo, redirectIfFound }: IParams) => {
  const { data, error } = useRequest("authed", isAuthed);

  const user = data?.data;
  const hasUser = user;

  useEffect(() => {
    if (!redirectTo) return;
    if (
      // If redirectTo is set, redirect if the user was not found.
      (redirectTo && !redirectIfFound && !hasUser) ||
      // If redirectIfFound is also set, redirect if the user was found
      (redirectIfFound && hasUser)
    ) {
      Router.push(redirectTo);
    }
  }, [redirectTo, redirectIfFound, hasUser]);

  return error ? null : user;
};
Run Code Online (Sandbox Code Playgroud)
//index.tsx
const Home: NextPage = () => {
  const user = useUser({ redirectTo: "/login" });

  if (user === undefined || user === false) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <Head>
        
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <div>Home</div>
    </div>
  );
};
Run Code Online (Sandbox Code Playgroud)

UseRequest Hook 返回 true 和 false 作为返回值。

max*_*eth 21

太长了;博士

确保在状态的帮助下,router.push()在所有可能的重新执行过程中仅调用一次:useEffect


const [calledPush, setCalledPush] = useState(false); // <- add this state

// rest of your code [...]

 useEffect(() => {
    if (!redirectTo) return;
    if (
      (redirectTo && !redirectIfFound && !hasUser) ||
      (redirectIfFound && hasUser)
    ) {
        // check if we have previously called router.push() before redirecting
      if (calledPush) {
        return; // no need to call router.push() again
      }

      Router.push(redirectTo);
      setCalledPush(true); // <-- toggle 'true' after first redirect
    }
  }, [redirectTo, redirectIfFound, hasUser]);

  return error ? null : user;
};

Run Code Online (Sandbox Code Playgroud)

背景

useEffect如果您有多个依赖项,则可能会被多次调用(启用React Strict 模式也会发生,但在这种情况下似乎没有错误),并且router.push()在不同的同一 Next.js 页面中(重新)调用多次在某些情况下,地方/整个不同的重新渲染似乎会导致此错误,因为冗余router.push()调用必须中止,因为当前的页面组件由于先前调用的成功而卸载router.push()

如果我们跟踪是否已经router.push通过calledPush状态调用(如上面的代码片段所示),我们将忽略潜在重新执行router.push()中的所有冗余调用,因为对于所有后续执行,状态值将已经更新为重新触发后触发的状态值。渲染,因此之后生效。useEffectuseEffectcalledPushtrueuseEffectsetCalledPush(true)


小智 5

我也遇到了类似的问题。push当网络速度较慢或短时间内多次触发该事件时,会报错。

我是这样解决的:

import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';

const useSafePush = () => {
  const [onChanging, setOnChanging] = useState(false);
  const handleRouteChange = () => {
    setOnChanging(false);
  };
  const router = useRouter();
  // safePush is used to avoid route pushing errors when users click multiple times or when the network is slow:  "Error: Abort fetching component for route"
  const safePush = (path: string) => {
    if (onChanging) {
      return;
    }
    setOnChanging(true);
    router.push(path);
  };

  useEffect(() => {
    router.events.on('routeChangeComplete', handleRouteChange);

    return () => {
      router.events.off('routeChangeComplete', handleRouteChange);
    };
  }, [router, setOnChanging]);
  return { safePush };
};

export default useSafePush;
Run Code Online (Sandbox Code Playgroud)

我观察routeChangeComplete事件,只有当路由改变完成时,push函数才会被调用。

用法:

  const { safePush } = useRouterChange();
  safePush(path)
Run Code Online (Sandbox Code Playgroud)