Синхронизировать состояние c с быстро происходящими событиями - PullRequest
2 голосов
/ 05 августа 2020

Я сделал настраиваемые хуки, отслеживающие переменную состояния, которая основана на количестве полученных событий сокета. Когда я тестирую, отправляя 10 одновременных событий, результат общей переменной состояния равен 6, 7 или 8, а не ожидаемым 10.

const useSocketAmountReceivedState = (event: string): number => {
    const [total, setTotal] = useState(0);

    useEffect(() => {
        Socket.on(event, () => {
            console.log(total);
            setTotal(total + 1);
        });

        return (): void => {
            Socket.off(event);
        };
    });

    return total;
}

Журналы выполнения выглядят примерно так:

0
1
1
2
3
3
4
4
4
5

Socket в приведенном выше примере - это реализация для веб-сокета.

Итак, я могу сделать вывод, что общее количество обновляется недостаточно быстро, но каков наилучший шаблон для обработки такого поведения?

Ответы [ 3 ]

2 голосов
/ 05 августа 2020

Событие Socket.on должно находиться вне функции useEffect

const useSocketAmountReceivedState = (event: string): number => {
    const [total, setTotal] = useState(0);
    Socket.on(event, () => {
        console.log(total);
        setTotal(total + 1);
    });
    useEffect(() => {
        return (): void => {
            Socket.off(event);
        };
    }, []);

    return total;
}
2 голосов
/ 05 августа 2020

Попробуйте указать пустой массив в качестве второго аргумента ловушки. Вы не хотите, чтобы это регистрировало событие каждый раз при рендеринге компонента.

const useSocketAmountReceivedState = (event: string): number => {
    const [total, setTotal] = useState(0);

    useEffect(() => {
        Socket.on(event, () => {
            console.log(total);
            setTotal(total + 1);
        });

        return (): void => {
            Socket.off(event);
        };
    }, [total]);

    return total;
}

UPDATE:

Я обновил свой первоначальный ответ и добавил Итого в массив зависимостей React Hook.

Обратите внимание, что второй аргумент, он же массив зависимостей. Это массив, который принимает состояние или свойство. И он инструктирует React запускать эту ловушку каждый раз, когда изменяется любой из элементов в массиве зависимостей.

Если вы передадите пустой массив, то ловушка будет запускаться только при начальной загрузке после монтирования компонента.

В вашем примере, если вы передаете пустой массив, он создает закрытие. Следовательно, итоговое значение всегда будет начальным значением.

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

0 голосов
/ 06 августа 2020

Коллега пришел с этим решением. Использование ссылки, для которой ссылка не прилагается.

const useSocketAmountReceivedState = (event: string): number => {
    const count = useRef(0);
    const [state, setState] = useState(0);

    useEffect(() => {
        Socket.on(event, () => {
            count.current++;
            setState(count.current);
        });

        return (): void => {
            Socket.off(event);
        };
    }, []);

    return state;
}
...