김정수*_*김정수 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)