Why might react-router navigate(-1) go back two routes/pages?

32 Views Asked by At

I've got a page which needs to kick a user back to the previous one if they don't have permissions to view. I made this very simple component as a test but I'm finding that it navigates back two pages not one. Any ideas why?

import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';

const GoBack = () => {
  const navigate = useNavigate();

  const [state, setState] = useState('init');

  if (state === 'init') setState('goBack');

  useEffect(() => {
    if (state === 'goBack') navigate(-1);
  }, [state]);

  return <p>You are not permitted to view this page</p>;
};

export default GoBack;
1

There are 1 best solutions below

0
quyentho On

You shouldn't call setState in the middle of the component's rendering process. This will cause the component to become impure. Strict mode helps you catch this bug early by causing the component to render twice, highlighting the inconsistency. What happened was:

Component first render -> react see useState("init") -> reach the if statement -> setState("goBack") -> the component re-render before reaching the useEffect -> rerender -> state is "goBack" -> run the effect -> navigate(-1) -> Strict mode makes the component run the second time -> navigate(-1) again.

You can use this to run with and without StrictMode to see the detail:

const GoBack = () => {
  // const navigate = useNavigate();

  const [state, setState] = useState("init");

  console.log("before setState:", state);
  if (state === "init") {
    console.log("setState");
    setState("goBack");
  }
  console.log("after setstate:", state);
  useEffect(() => {
    console.log("inside useEffect:", state);

    if (state === "goBack") {
      console.log("navigate(-1)", state);
      // navigate(-1);
    }
  }, [state]);

  return null;
};

Move the if check into the useEffect and the problem is gone. If your intend was to prevent users from seeing anything on the screen then you can use useLayoutEffect