简体   繁体   中英

Can't perform a React state update on an unmounted component with EventListener

I have the following piece of code on which I am getting warning two warnings:

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.

unmountComponentAtNode(): The node you're attempting to unmount was rendered by another copy of React.

    import React, { useState, useEffect } from "react";
    import GravatarList from "./GravatarList";
    import Header from "./Header";
    import { calculateNumberOfImages } from "./utils";
    
    const App = () => {
      const handle = () => {
        setState({ images: calculateNumberOfImages() });
      }
    
    
      useEffect(() => {
          return () => {
    
            window.removeEventListener('resize', () => handle())
            window.removeEventListener('scroll', () => handle())
          }
       }, [])
    
    
      const [state, setState] = useState(() => {
        
        window.addEventListener("scroll", () => handle());
        window.addEventListener("resize", () => handle());
      
        return { images: calculateNumberOfImages() };
      });
    
      return (
        <div>
          
          <Header />
          <GravatarList state={state} />
        </div>
      );
    };
    
    export default App;

I can't seem to figure out what I am doing wrong as I have already cleared the listeners in useEffect .

The issue here is that the event callbacks you are trying to remove aren't the same callbacks you added to begin with. The issue is because you are using anonymous functions to call the function updating state.

You should also not use the state initializer function to do side effects like adding event listeners.

Move the handle callback and adding of event listeners into the mounting useEffect hook. Pass the handle callback reference to the add/remove functions,

const App = () => {
  const [state, setState] = useState(() => ({
    images: calculateNumberOfImages()
  }));

  useEffect(() => {
    const handle = () => {
      setState({ images: calculateNumberOfImages() });
    };

    window.addEventListener("scroll", handle);
    window.addEventListener("resize", handle);
  
    return () => {
      window.removeEventListener('resize', handle);
      window.removeEventListener('scroll', handle);
    }
   }, []);

  return (
    <div>
      <Header />
      <GravatarList state={state} />
    </div>
  );
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM