How to fix React Warning : Can't perform a React state update on an unmounted component
Asked Answered
R

1

13

Whenever if there is any asynchronous task performing related to component and that component unmounts then React generally gives this warning -

Can't perform a React state update on an unmounted component This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

I found some solutions over internet to use isMount flag (either by using it with useRef or useState) as true and then updating it to false on component unmount. But is that a proper solution as per React site using isMount is a antipattern.

https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html

Roccoroch answered 24/2, 2022 at 21:41 Comment(1)
This issue usually happens when you are trying to apply state changes to a component that does not exist anymore.Misdeem
P
23

In future version of React, you probably won't need to fix this. As React dev team is going to remove this warning in future release. The main reason being this warning can be false positive sometimes.

As per this commit by Dan Abramov https://github.com/facebook/react/pull/22114

But what are the solutions to fix this till that version release -

  1. Using isMountState anti-pattern - If someone is checking isMounted in his code to fix this issue, then that person is already too late in performing this check, as this warning indicates the same check is done by React and it failed.

  2. If this issue is because of an asynchronous call. Then one possible solution is to use AbortController API in your code. AbortController API helps in aborting any ajax call that is already made. Cool stuff. Right?

More details on this can be found here

Abort Controller1

So if it is a fetch API one can use AbortController API like this

useEffect(() => {
  const abortController = new AbortController()
  // creating an AbortController
  fetch(url, {
      signal: abortController.signal
    })
    // passing the signal to the query
    .then(data => {
      setState(data)
      // if everything went well, set the state
    })
    .catch(error => {
      if (error.name === 'AbortError') return
      // if the query has been aborted, do nothing
      throw error
    })

  return () => {
    abortController.abort()
    // stop the query by aborting on the AbortController on unmount
  }
}, [])

If you are using axios, then good news is axios also provides support for AbortController APIs -

const fetchData = async (params) => {
        setLoading(true);
        try {
            const result = await axios.request(params);
            // more code here 

        } catch (curError) {
            if (axios.isCancel(curError)) {
                return false;
            }
            // error handling code 
        }
        return null;
    };

    useEffect(() => {
        const cancelToken = axios.CancelToken;
        const source = cancelToken.source();

            fetchData({
                ...axiosParams,
                cancelToken: source.token
            });
        
        return () => {
            source.cancel("axios request cancelled");
        };
    }, []); 
Paulita answered 24/2, 2022 at 22:5 Comment(1)
CancelToken deprecatedLeges

© 2022 - 2024 — McMap. All rights reserved.