@Mjogan

Как правильно организовать работу с socket.io в SPA с подключением и без подключения к комнатам?

Добрый день.
В SPA приложении я подключаю пользователя к сокету, как только он будет авторизован
useEffect(() => {
    if (isAuth) {
      dispatch(
        SocketActionCreators.setSocket(
          io(API_URL, {
            transports: ['websocket'],
            path: '/server',
          })
        )
      );
    } else if (socket && !isAuth) {
      socket.disconnect();
    }
  }, [isAuth]);

На страницах мероприятия (socket room, по факту) я подключаю его к комнате и регистрирую обработчики и тд
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]);


Проблема в следующем: на странице мероприятия мне как-то надо показывать пользователю, что произошла потеря соединения, что оно будет восстановлено, как только связь появится.

для этого в последнем useEffect-е я добавил:
// переменная для предотвращения показа сообщения о восстановлении связи
      // при первом подключении
      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,
          })
        );
      });

все нормально, но есть три проблемы:
1) эти обработчики сработают на других страницах после размонтирования этого компонента (в целом, понятно, почему). я пытался их удалить так: socket.removeAllListeners(["connect", "disconnect"]), но это не работает, работает только удаление всех socket.removeAllListeners() - это не выход... как можно оповещать пользователя только на данной странице ?
2) после возобновления связи с сервером подключение с сокетом восстанавливается, но к комнате пользователь не присоединится до перезагрузки страницы, т.к. у меня для этого отдельный emit: socket.emit('user:join-webinar', { user, webinarId }). Можно ли как-то сделать это автоматически?
3) как можно разрывать соединение на старой вкладке, если пользователь пытается открыть несколько копий страницы?
  • Вопрос задан
  • 100 просмотров
Пригласить эксперта
Ответы на вопрос 1
@Mjogan Автор вопроса
Если кому-то это поможет, ответ на 2й вопрос:
восстановить связь с комнатой при реконнекте можно просто поместив emit на запрос присоединения внутрь обработчика connect
socket.on('connect', () => {
  socket.emit('user:join-webinar', { user, webinarId });
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы