I
I
Ivan2021-10-25 15:14:59
Node.js
Ivan, 2021-10-25 15:14:59

How to properly organize work with socket.io in SPA with and without connection to rooms?

Good afternoon.
In a SPA application, I connect the user to the socket as soon as he is authorized

useEffect(() => {
    if (isAuth) {
      dispatch(
        SocketActionCreators.setSocket(
          io(API_URL, {
            transports: ['websocket'],
            path: '/server',
          })
        )
      );
    } else if (socket && !isAuth) {
      socket.disconnect();
    }
  }, [isAuth]);

On the pages of the event (socket room, in fact) I connect it to the room and register handlers, etc.
useEffect(() => {
    if (socket) {
      socket.emit('user:join-webinar', { user, webinarId });

      socket.on('users:get', (rosters) => {
        dispatch(CurrentWebinarActionCreators.setRosters(rosters));
      });

      socket.emit('message:get', webinarId);

      socket.on('messages', (messages) => {
        dispatch(CurrentWebinarActionCreators.setMessages(messages));
      });

      socket.on('chat:status', (status) => {
        dispatch(CurrentWebinarActionCreators.setChatIsAvailable(status));
      });

      return () => {
        socket.emit('user:left-webinar', { user, webinarId });
      };
    }
  }, [webinarId, socket]);


The problem is this: on the event page, I somehow need to show the user that the connection has been lost, that it will be restored as soon as the connection appears.

for this in the last useEffect I added:
// переменная для предотвращения показа сообщения о восстановлении связи
      // при первом подключении
      let firstConnection = true;

      socket.on('connect', () => {
        if (!firstConnection) {
          message.success({
            content: 'Связь восстановлена',
            key: 'updatable',
            duration: 2,
          });
        }
      });

      socket.on('disconnect', () => {
        firstConnection = false;
        message.error({
          content: 'Потеря соединения',
          key: 'updatable',
          duration: 2,
        }).then(() =>
          message.loading({
            content: 'Пытаемся восстановить подключение...',
            key: 'updatable',
            duration: 0,
          })
        );
      });

everything is fine, but there are three problems:
1) these handlers will work on other pages after this component is unmounted (in general, it is clear why). i tried to remove them like this: socket.removeAllListeners(["connect", "disconnect"]) , but it doesn't work, only removing all socket.removeAllListeners() works - that's not an option... how can you notify the user only on this page ?
2) after the resumption of communication with the server, the socket connection is restored, but the user will not join the room until the page is reloaded, because I have a separate emit for this: socket.emit('user:join-webinar', { user, webinarId }) . Is there any way to do this automatically?
3) How can you break the connection on the old tab if the user tries to open multiple copies of the page?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
I
Ivan, 2021-10-25
@Mjogan

If it helps someone, the answer to the 2nd question:
you can restore communication with the room when reconnecting by simply placing an emit on the join request inside the connect handler

socket.on('connect', () => {
  socket.emit('user:join-webinar', { user, webinarId });

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question