reactjstypescriptsocket.iotslint

UseEffect cleanup in socket.io-client


useEffect(() => {
  if (authUser) {
    const socket = io("http://localhost:5000", {
      query: {
        userId: authUser._id,
      },
    });

    setSocket(socket);

    socket.on("getOnlineUsers", (users: string[]) => {
      setOnlineUsers(users);
    });

    // the error disappeared when removing this line
    return () => socket.close();

  }
  else {
    if (socket) {
      socket.close();
      setSocket(null);
    }
  }
}, [authUser, socket]);

I got this weird error stating

Argument of type '() => (() => Socket<DefaultEventsMap, DefaultEventsMap>) | undefined' is not assignable to parameter of type 'EffectCallback'.
  Type '(() => Socket<DefaultEventsMap, DefaultEventsMap>) | undefined' is not assignable to type 'void | Destructor'.
    Type '() => Socket<DefaultEventsMap, DefaultEventsMap>' is not assignable to type 'void | Destructor'.
      Type '() => Socket<DefaultEventsMap, DefaultEventsMap>' is not assignable to type 'Destructor'.
        Type 'Socket<DefaultEventsMap, DefaultEventsMap>' is not assignable to type 'void | { [UNDEFINED_VOID_ONLY]: never; }'

I don't fully understand the error. Would someone be kind enough to help me with this, please? Thank you in advance.


Solution

  • This is the type of the callback inside useEffect. The return value from useEffect callbacks should either be

    1: a function that returns type void

    enter image description here

    1. or a Destructor which are also allowed to only return void.

    enter image description here

    But socket.close which is a synonym of socket.disconnect returns a Socket instance.

    Since arrow functions (without braces) simplicity return the expression inside, you can wrap it in curly braces to remove the TS error:

    return () => {
    socket.close();
    }