Every page goes through an AuthGuard
component which determines if child components can be shown or if the user needs to be redirected to another page.
It works well when first visiting a page, but I’ve noticed some weird behavior when going back to the previous page. For example:
- I’m not logged in and go to
/home
, which is only shown for logged in users. I get redirected to/login
, which is correct. - I click in my browser (top left) to go to the previous page. Note that I don’t go to the previous page by clicking on a link on the website.
- For less than a second, I can see the content of
/home
, then I get redirected back to/login
, which is handled byAuthGuard
.
I use a boolean state hook for showing children and noticed that it’s still set to true
for a tiny bit when going back to the previous page. true
is still the old value it got when loading /login
. Why doesn’t it start afresh?
Here’s my 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 />;
}
I set the restriction in a page through getStaticProps
, like:
export async function getStaticProps() {
return {
props: {
restriction: "public",
},
};
}
2
Answers
I was able to get it working by also saving the route in a state hook. However, I see it as a dirty fix and would love to know more about why is this happening in the first place.
a simple solution can achieve this is by watching the route in useEffect and whenever it changes clear or reset the state
import {useRouter} from ‘next/router’
const Page = (props) => {
const [state, setState] = useState(someState)
const pageRoute = useRouter().asPath
useEffect(() => {
setState(resetState) // When the page route changes the state will reset.
}, [pageRoute])