1

I am using Socket.io Callbacks with react. However, sometimes I get this warning

Warning: Can't call setState (or forceUpdate) 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 the componentWillUnmount method.

Fundamentally, I understand that the callback can be holding references to local data and preventing that data from being cleared until the callback is cleared.

Unfortunately Socket.io does not work with promises but with direct callbacks. What this means is that I may get a callback AFTER the component has unmounted since these callbacks cannot be "cancelled"

I make sure that the server responds to all callbacks to make sure they get satisfied and therefore do not leak memory

I attempted to "silence" this warning by calling this.setState({mounted:true}); in componentDidMount and this.setState({mounted:false}); in componentWillUnmount

And then within my update simply checking if(this.state.mounted) before calling this.setState() within the socket.io callback.

This works for most cases. However it seems that in this case. The parent component causes this component

  • componentDidMount
    • update state to mounted:true
    • send request to socket.io -componentWillUnmount
    • update state to mounted:false
  • componentDidMount
    • update state to mounted:true
    • send additional request to socket.io
  • Callback response from socket.io
    • warning printed

How do I prevent this? Is there a better design pattern for sock.io

Jim
  • 2,034
  • 2
  • 15
  • 29
  • I'm not sure exactly how, but maybe you can "unlisten" to certain events with `off` when `componentWillUnmount` is called, so that you have no inactive listeners lying around. – Tholle Jul 03 '18 at 22:27
  • Yeah this isnt an event but instead a callback response to socket.io. So Client sends an event to the server that includes a callback function. The server can then call the callback function at any time. – Jim Jul 04 '18 at 03:04

2 Answers2

0

Based on this to another socket.io related question, I would say that instead of checking the mounted state and then based on that calling setState, you may want to actually disconnect from the server on component unmount. As you have it right now, the server will still respond to the event even after the component is no longer mounted, but if you disconnect when the component is unmounted no data will get sent from the server at all.

NOTICE: I did not try this myself, so I can't say for sure that this will work, but based on the above answer, I believe this may solve your issue.

Chaim Friedman
  • 6,124
  • 4
  • 33
  • 61
  • I am using the same socket in many other components, for a single page app so disconnecting is not really a viable option in this case. – Jim Jul 04 '18 at 03:00
0

I found a response here:

Is there a way to check if the react component is unmounted?

They suggest using:

this._ismounted = true;
this._ismounted = false;

instead of calling this.setState() which is asynchronous

It seems you should from the documentation https://reactjs.org/docs/react-component.html

You should not call setState() in componentWillUnmount() because the component will never be re-rendered. Once a component instance is unmounted, it will never be mounted again.

Jim
  • 2,034
  • 2
  • 15
  • 29