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 колбэка эффекта, но код выглядит несуразно.
