每个页面都要经过一个AuthGuard
组件,该组件决定是否可以显示子组件,或者是否需要将用户重定向到另一个页面。
当第一次访问一个页面时,它工作得很好,但我注意到当返回到前一个页面时,一些奇怪的行为。例如:
- 我没有登录,去
/home
,这只显示登录用户。我重定向到/login
,这是正确的。 - 我在浏览器中点击(左上角)转到上一页。请注意,我不会通过点击网站上的链接转到上一页。
- 不到一秒钟,我可以看到
/home
的内容,然后我被重定向回/login
,这是由AuthGuard
处理。
我使用布尔状态钩子来显示孩子,并注意到当返回到上一页时,它仍然被设置为true
。true
仍然是加载/login
时得到的旧值。为什么不重新开始呢?
我的AuthGuard
:
const AuthGuard = ({ children, restriction }) => {
const [canShowChildren, setCanShowChildren] = useState<boolean>(false);
const { user, loading } = useAuth();
const router = useRouter();
// I need to use useEffect & async because some user data can only be retrieved
// asynchronously, though I haven't included that part here because it's
// irrelevant to the problem.
useEffect(() => {
(async () => {
if (loading || !router.isReady) return;
if (restriction === "public") {
setCanShowChildren(true);
return;
}
if (!user) {
router.push("/login");
return;
}
...
})();
}, [loading, restriction, router, user]);
if (loading || !router.isReady) {
return <Loading />;
}
return canShowChildren ? children : <Loading />;
}
我通过getStaticProps
在页面中设置限制,如:
export async function getStaticProps() {
return {
props: {
restriction: "public",
},
};
}
一个简单的解决方案是通过在useEffect中观察路由,当它改变时清除或重置状态
从'next/router'中导入{useRouter}
const Page = (props) =>{
const [state, setState] = useState(someState)
const pageRoute = useRouter().asPath
useEffect(() =比;{setState(resetState)//当页面路由改变时,状态将重置。}, [pageRoute])
我还可以通过在状态钩子中保存路由来让它工作。然而,我认为这是一个肮脏的修复,并希望更多地了解为什么会发生这种情况。
const AuthGuard = ({ children, restriction }) => {
const [canShowChildren, setCanShowChildren] = useState<boolean>(false);
const { user, loading } = useAuth();
const router = useRouter();
const [route, setRoute] = useState<string>("");
useEffect(() => {
(async () => {
if (router.asPath !== route) setCanShowChildren(false);
setRoute(router.asPath);
...
})();
}, [loading, restriction, router, user, pageRoute]);
if (loading || !router.isReady || router.asPath !== route) {
return <Loading />;
}
...
};