1

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

Mark
  • 731
  • 2
  • 10
  • 29
  • If you persist "amount" state in "AppContext" and a user do a page refresh, "amount" state will be it's default value. Are you sure of this? "when you do a page refresh it directs you back to page-1 even when there is an amount set." – Deniz Nov 21 '21 at 22:58
  • 1
    Exactly. Even when there is an `amount` set, on page refresh on `page-2` it directs back to `page-1`. When console logging amount you can see it is there. Maybe I'll setup a quick CodeSandBox to elaborate myself more. – Mark Nov 21 '21 at 23:15
  • 2
    You get undefined for a split second causing the redirect back to page-1. – Rolando Yera Nov 22 '21 at 01:05
  • It is weird because when the amount is set, it is being stored in localStorage as well. Any idea on how to fix this? Perhaps there is a better approach to handle this. – Mark Nov 22 '21 at 01:39

2 Answers2

1

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("");
};
juliomalves
  • 42,130
  • 20
  • 150
  • 146
0

Change null to an empty string ("") instead of (null) in your clearAmount function and in useState("") in the _app file. Also, change your if statement to if (amount === ""). That fixes it, here's a sandbox that I forked from yours. https://codesandbox.io/s/next-js-userouter-with-useeffect-forked-t2enf?file=/pages/page-2.js

Rolando Yera
  • 820
  • 4
  • 12
  • I think we are almost there. The problem is that on a 'fresh' page visit you are still able to visit `page-2` directly and stays on `page-2` and displays: `The amount is: null`. Instead it should re-direct back to `page-1` as well. – Mark Nov 22 '21 at 03:11
  • Add the same empty string to useState("") in the _app. I updated the answer.. – Rolando Yera Nov 22 '21 at 03:49
  • I hate to be the bringer of bad news, but now when you select an amount on `page-1` then on `page-2` refresh the page. It will re-direct you back to `page-1` – Mark Nov 22 '21 at 04:08