У вас есть устаревшее закрытие, это распространенная ошибка, которая часто допускается при использовании хуков с зависимостями (таких как useEffect
, useMemo
, useCallback
). Взгляните здесь .
Решение состоит в том, чтобы всегда включал все переменные, которые вы собираетесь использовать в обратном вызове useEffect
, в список зависимостей . В вашем случае их трудно обнаружить, потому что большинство из них скрыты внутри функции connectToWebSocket
, которая обновляется при каждом рендеринге, кроме ... вызываемой useEffect
является та, которая была создана в первый рендеринг, и обратный вызов onmessage
закрывается по состоянию, которое компонент имел при первом рендеринге.
Поскольку вы используете WebSocket, недостаточно просто useEffect
каждый раз, когда ваш history
изменения, потому что тогда у вас будет несколько соединений (по одному на каждое изменение), вам также нужно будет отключиться при вызове следующего эффекта, и вы можете сделать это, возвращая функцию из обратного вызова useEffect
, который отключается от WebSocket , так что эффект может подключиться снова. Это также пример, который концептуально объясняется в документах React при показе примера об useEffect.
Что-то, что часто предлагается, чтобы избежать такой ситуации, это
- Определите функцию, которую вы будете вызывать в обратном вызове
useEffect
внутри самого обратного вызова, а не вне его; - Используйте свой любимый линтер, чтобы предупредить вас о пропавших зависимостях в вашем
useEffect
(или аналогичные) звонки. Если вы попробуете create-react-app
, это уже настроено для вас.
Также, как предполагает @ ako-javakhishvili, всякий раз, когда ваше следующее состояние зависит от предыдущего значения самого состояния, вызывайте функцию setter. с обратным вызовом вместо немедленного значения. Это решит вашу проблему в этом случае, но у вас все еще будет несвежее закрытие, и вы должны позаботиться об этом.