In my project, I jumped to another page before the web request was returned and found that the console reported an error:

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.

The request in the project is written similar to the following:

  useEffect(() => {
    const reqData = async() => {
      try {
        const res: any = await axios('xxxxx');
        setData(res);
      } catch(err) {
        console.log(err);
      }
    }
    reqData();
  }, []); 

Error: Analysis:
The error tells us that we cannot perform a state update on the uninstalled component, it indicates that there is a memory leak in the application.
The reason is that before the request returns, the user makes a page jump, after which the current component is uninstalled. After the uninstallation, the request returns and the code after the await is executed to perform a state update on the component. However, the component has already been uninstalled, which is why the error is reported.

Solution:
After checking out the react documentation, I know that I can handle unordered responses through local variables inside useEffect:

  useEffect(() => {
  	let ignore = false;
    const reqData = async() => {
      try {
        const res: any = await axios('xxxxx');
        if (!ignore) { 
          setData(res);
        }
      } catch(err) {
        console.log(err);
      }
    }
    reqData();
    return () => { ignore = true };
  }, []); 

This way the state update is not performed after the component is uninstalled

The above approach works for components that only initiate a request to update state when they are initialised. However, if there are components that initiate state update requests after certain events are triggered, we need a different approach to prevent memory leaks.
You can use useRef to create a new ref object to record whether the current component has been uninstalled or not. This can be used to prevent memory leaks by determining whether the component has been uninstalled or not before updating its state after a successful request.

const App = () => {
  const [data, setData] = useState([]);
  const isUnmounted = useRef(false);
  
  useEffect(() => {
    return () => {
      isUnmounted.current = true;
    }
  }, [])

  const handleClick = async() => {
    const res: any = await axios('xxxx');
    if (!isUnmounted.current) { 
      setData(res);
    }
  }
  return (
    <>
      <button onClick={handleClick}>Click to get the data</button>
      ...
    </>
  )
} 

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *