Search code examples
node.jsreactjswebsocketsocket.ioflux

Reconnect socket on user login


I work with a setup created by create-react-app and use flux for data management and the application needs to implement socket on the client side (I use socket.io for this purpose).

Currently the socket is initialised in a Socket.js file the following way:

import io from 'socket.io-client';
import { remoteUrl } from './constants/RemoteUrl';
import SocketWorker from './utilities/SocketWorker';

let socket = io.connect(remoteUrl + '?role=user');

socket.on('statusChange', (data) => {
  return SocketWorker.receiveOrderStatusChange(data);
})

export  { socket };

It does work, however the problem is that it only tries to connect to the server once, when the site is loaded. When the user opens the site unauthenticated it does not connect and misses to reconnect, thus the connection is not established and socket events are not received

I have tried to create a class instead and react an API for reconnect on the object, like:

import io from 'socket.io-client';
import { remoteUrl } from './constants/RemoteUrl';
import SocketWorker from './utilities/SocketWorker';

function Socket() {
  this.socket = io.connect(remoteUrl + '?role=user');
  this.reconnect = () => {
    this.socket = io.connect(remoteUrl + '?role=user');
  }
}

let socket = new Socket();

socket.socket.on('statusChange', (data) => {
  return SocketWorker.receiveOrderStatusChange(data);
})

export { socket };

I tried to call the Socket.reconnect() method, although it did not work and connection was not established either. Any idea or alternative solution?


Solution

  • The way I managed to solve this if anyone face the same problem with the Socket.io API:

    First, you should encapsulate your Socket into an object created by the constructor, but there is no need to create a reconnect method as the connection is present already (and the auth can be handled through emitted events I will describe below) :

    import io from 'socket.io-client';
    import { remoteUrl } from './constants/RemoteUrl';
    import SocketWorker from './utilities/SocketWorker';
    
    function Socket() {
      this.socket = io.connect(remoteUrl + '?role=user');
    
      this.socket.on('statusChange', (data) => {
        return SocketWorker.receiveOrderStatusChange(data);
      })
    };
    
    const socket = new Socket();
    
    export  { socket };
    

    You can import the socket anywhere within your project:

    import {socket} from './Socket';
    

    And you can call:

    socket.socket.emit('joinRoleRoom','user');
    socket.socket.emit('joinIdRoom', _user._id);
    

    On the server side, you just need to handled these events as follow:

    socket.on('joinRoleRoom', (role) => {
      socket.join(role)
      console.log('Client joined to: ' + role);
    });
    socket.on('joinIdRoom', (id) => {
      console.log('Client joined to: ' + id);
      socket.join(id)
    });
    

    The socket will join the necessary rooms based on their auth info obtained during the auth process.