Warning to make a cleanup function in useEffect() occurs occasionally

Viewed 859

I am using AWS-Amplify and when a user signs out I get a warning:

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.

It mentions it occurs in the Profile.tsx file and this is the useEffect() hook.

But the issue is that the error occurs sometimes.

I keep testing it out and it comes and goes and I have no idea why it is so.

 function Profile() {

  const [user, setUser] = useState<IIntialState | null>(null);

  useEffect(() => {
    checkUser();
    Hub.listen("auth", data => {
      const { payload } = data;
      if (payload.event === "signOut") {
        setUser(null);
      }
    });
  }, []);

  async function checkUser() {
    try {
      const data = await Auth.currentUserPoolUser();
      const userInfo = { username: data.username, ...data.attributes };
      console.log(userInfo);
      setUser(userInfo);
    } catch (err) {
      console.log("error: ", err);
    }
  }
  function signOut() {
    Auth.signOut().catch(err => console.log("error signing out: ", err));
  }
  if (user) {
    return (
      <Container>
        <h1>Profile</h1>
        <h2>Username: {user.username}</h2>
        <h3>Email: {user.email}</h3>
        <h4>Phone: {user.phone_number}</h4>
        <Button onClick={signOut}>Sign Out</Button>
      </Container>
    );
  }
  return <Form setUser={setUser} />;
}
2 Answers

I happens because you component unmounts but you still have subscriptions in it.

React useEffect provides unmount function:

  useEffect(() => {
    Hub.listen("auth", func);
    return () => {
    // unsubscribe here
     Hub.remove("auth", signOut)
    };
 });

And you Hub Class has remove method

remove(channel: string | RegExp, listener: HubCallback): void

Remove your subscription in useEffect return function

Hub.remove()

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 message is straightforward. We're trying to change the state of a component, even after it's been unmounted and unavailable.

There are multiple reasons why this can happen but the most common are that we didn’t unsubscribe to a websocket component, or this were dismount before an async operation finished. to solve this you can either do this :

 useEffect(() => {
    checkUser();
    //check howto remove this listner in aws documentation  
    const listner= Hub.listen("auth", data => {
      const { payload } = data;
      if (payload.event === "signOut") {
        setUser(null);
      }
    });

    //this return function is called on component unmount 
    return ()=>{/* romve the listner here */}
  }, []);

or go with this simple approach .

 useEffect(() => {
    let mounted =true
    Hub.listen("auth", data => {
      const { payload } = data;
      if (payload.event === "signOut" && mounted ) {
        setUser(null);
      }
    });


     //this return function is called on component unmount 
    return ()=>{mounted =false }
  }, []);

Read more about this here.

Related