27

The changes to strict-mode in React version 18 causes my code to render twice, which causes an error in axios abort controller, but I don't know how to clear the error from the browser console after the app renders twice.

Please note: I am working on a sign-up / log-in app and even after I successfully logged in, React takes me back to the log-in page, because of the axios error

useEffect(() => {
    let isMounted = true;
    // used by axios to cancel request
    const controller = new AbortController();

    const getGoals = async () => {
        try {
            const response = await goalPrivate.get("/goals", {
                // option to cancel request
                signal: controller.signal
            })
            console.log(response?.data);
            // set goals state when component mounts
            isMounted && setGoals(response?.data);
        } catch (error) {
            console.log(error.message);
            // when refreshToken expires
            navigate("/login", { state: { from: location }, replace: true });
        }
    }

    getGoals();

    // cleanup function
    return () => {
        // don't set state if component unmounts
        isMounted = false;
        // cancel request if component unmounts
        controller.abort();
    }
    
    // eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
2
  • 1
    If you just care about console message, you can safely ignore it since you won't have it in production. What is the error by the way ? Commented Jun 3, 2022 at 11:52
  • @CesarePolonara it prevents me from accessing the other parts of my code. Commented Jun 3, 2022 at 11:53

6 Answers 6

24

React StrictMode calls all Effects twice to make sure their cleanup/unmount handlers work as intended. You may need to change your effects accordingly, even if they have an empty dependency list and would normally not unmount before the site is closed.

Note, this only happens in Strict + development mode. In a production build, effects will only be called once and when their dependencies change.

Fore more context, see https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state

Sign up to request clarification or add additional context in comments.

1 Comment

For a more detailed answer stackoverflow.com/a/72238236/15288641
10

Had the same problem and fixed it this way.

When the abortController is aborted you jump to the catch so you just check if the signal is aborted or not to execute the rest of your code.

useEffect(() => {
    const abortController = new AbortController();

    fetch("https://pokeapi.co/api/v2/pokemon", {
      signal: abortController.signal,
    })
      .then((res) => res.json())
      .then(console.log)
      .catch((err) => {
        if (abortController.signal.aborted) return;
        console.log(err);
        // Your navigate
      });

    return () => {
      abortController.abort();
    };
  }, []);

1 Comment

Basically, you should correctly clean all applied effects? - Http call = Http cancel - setInterval() = clearInterval() - .. and so on
3

React 18 now has Strict.Mode which can mount, unmount, and remount components which causes the abortController to issue an error on the first unmount. Remember, this only happens in development mode when Strict.Mode is applied in your index.js. We can check for that behaviour while in development-mode.

try {
     // fetch API data
  } catch (error) {
       if (process.env.NODE_ENV === "development" && error) {
         // ignore the error
        console.log(error.message);
   } else {
     // when refreshToken expires, go back to login
    navigate("/login", { state: { from: location }, replace: true });
  }
}

Comments

1

If you have the StrictMode enabled, it will fire two times the useEffect on development mode to make sure that you are aware of the possible side-effects that could appear.

1 Comment

I think the error is from axios abort controller, which runs when component un-mounts.
1

You should classify the error response depends on error code or http status code.

Eg:

...
try {
    // Create axios request
} catch (e: AxiosError) {
    if (error.code === 'ERR_CANCELED') {
        // When abort controller executed
    } else (error.response.status == 401) {
        // When you get http code 401 (Un-authenticated)
        // Eg:
        navigate("/login", { state: { from: location }, replace: true });
    } else {
        // Etc...
    }
}
...

Comments

0

Searching about this issue, I found that the best options to overcome this are:

  1. Remove the StrictMode from your app (you can do this simply by removind the StricMode tag from the App component)
  2. Use React Query (which you should be using in modern React applications anyway)

References:

https://javascript.plainenglish.io/react-18-useeffect-double-call-for-apis-emergency-fix-724b7ee6a646

https://blog.bitsrc.io/react-v18-0-useeffect-bug-why-do-effects-run-twice-39babecede93

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.