React Теряется соединение с топиком WebSocket

В компоненте есть useEffect, в котором происходит подписка на топик в сокет-соединении. handleReceiver - это функция, обернутая в useCallback, которая является хендлером сообщений из топика.

Проблема в том, что useEffect срабатывает дважды - и дважды происходит подписка, причем после первой подписки происходит мгновенно отписка - так устроен колбэк эффекта. Бэк не успевает обработать сообщение на подписку и отписку одновременно, поэтому иногда подписка теряется (даже несмотря на то, что после отписки идет заново подписка - см. скриншот ниже), и приложение в итоге работает без сообщений по каналу.

  useEffect(() => {
    if (deviceId) {
      const subscriber = cable.addSubscribe(
        { channel: 'Users::DeviceChannel' },
        handleReceiver,
      );

      return (): void => cable.removeSubscribe(subscriber);
    }

    return (): void => {};
  }, [deviceId, handleReceiver]);

На скриншоте ниже видно, что по таймингам unsubscribe и повторный subscribe отправляются одновременно - в этом и проблема.

Иными словами, cleanup-функция эффекта и повторный вызов эффекта вызываются одновременно - бэк иногда не понимает, какой из сообщений обработать первым. Можно ли как-то последовательно отправлять их? Пытался через throttle, - не помогло.

Скрин

Как быть? Убрать из массива зависимостей функцию, чтобы не происходил повторный вызов useEffect, не могу - она зависит от параметров, поэтому хендлер может быть разный.

UPDATE

Переписал хук вот так:

  const isSubscribed = React.useRef(false);

  React.useEffect(() => {
    let subscription: Channel | null = null;

    const setSubscription = (): void => {
      subscription = cable.addSubscribe(
        {
          channel: 'Users::DeviceChannel',
        },
        handleReceiver,
      );
    };

    if (id) {
      if (isSubscribed.current) setTimeout(setSubscription, 100);
      else setSubscription();

      isSubscribed.current = true;
    }

    return (): void => {
      if (id) {
        cable.removeSubscribe(subscription);
      }
    };
  }, [deviceId, handleReceiver]);

Теперь повторная подписка происходит после cleanup колбэка эффекта, но код выглядит несуразно.


Ответы (0 шт):