I am running into an issue with useRouter
and useEffect
where I want to re-direct the user if a certain condition is not met.
On page 1 you select an amount
which is passed into a context and is retrieved on page 2.
On page 2 I have this condition:
import { useEffect, useContext } from "react";
import { useRouter } from "next/router";
import AppContext from "../context/AppContext";
const PageTwo = () => {
const { amount } = useContext(AppContext);
const router = useRouter();
useEffect(() => {
if (!amount || amount == null) {
router.push("/page-1"); // redirect if no amount is selected
}
});
return (
...
);
};
When we land on page 2 I have the amount
but when you do a page refresh it directs you back to page-1
even when there is an amount
set. It works fine when you go straight to page-2
, without selecting an amount on page-1
, it re-directs you back to page-2
.
I might be getting something wrong here in how the Context API and or useRouter and useEffect work in this case.
Here is a CodeSanBox example with the issue:
https://codesandbox.io/s/next-js-userouter-with-useeffect-6645u?file=/pages/page-2.js
That behaviour occurs because even after setting a new amount
value in context, when reloading the page its initial value will be null
on first render which happens before the app checks and sets the localStorage
value. This triggers the redirect before the setAmount(amount)
is called with the stored value from localStorage
.
To prevent this with minimal changes, you could modify the check that triggers the redirect to the following. Making sure to also add amount
to the useEffect
's dependencies array.
useEffect(() => {
if (amount === "") {
router.push("/page-1");
}
}, [amount]);
You'd also have to change the value passed to setAmount
in _app
to default to empty string if no value is stored.
useEffect(() => {
const amount = localStorage.getItem("amount") ?? "";
setAmount(amount);
}, []);
This allows us to have a different values for the initial state value (null
) and empty value (""
). Meaning the redirect will not happen before amount
is updated with the value stored in localStorage
.
Finally, to keep the logic consistent, you have to update the clearAmount
function to set amount
to the empty value.
const clearAmount = () => {
setAmount("");
};