Мне нужно подключиться к серверу WebSockets и регистрировать его сообщения. С компонентом класса React я поместил бы эту логику c в componentDidMount
ловушку жизненного цикла и продолжил бы счастливо, но я не уверен, как правильно реализовать ее с помощью ловушек.
Вот моя первая попытка.
import React, {useEffect} from 'react';
export default function AppWs() {
useEffect(() => {
let ws = new WebSocket('wss://ws.kraken.com/');
ws.onopen = () => console.log('ws opened');
ws.onclose = () => console.log('ws closed');
ws.onmessage = e => {
const message = JSON.parse(e.data);
console.log('e', message);
};
return () => {
ws.close();
}
}, []);
return (
<div>hooks + ws</div>
)
}
Я добавил логин подключений и журналов c к useEffect
, предоставил пустой массив с зависимостями, и все работало отлично. Пока мне не нужно было добавить pause
состояние, чтобы приостановить ведение журнала.
export default function AppWs() {
const [isPaused, setPause] = useState(false);
useEffect(() => {
let ws = new WebSocket('wss://ws.kraken.com/');
ws.onopen = () => console.log('ws opened');
ws.onclose = () => console.log('ws closed');
ws.onmessage = e => {
if (isPaused) return;
const message = JSON.parse(e.data);
console.log('e', message);
};
return () => {
ws.close();
}
}, []);
return (
<div>
<button onClick={() => setPause(!isPaused)}>{isPaused ? 'Resume' : 'Pause'}</button>
</div>
)
}
ESLint начал кричать на меня, что я должен добавить isPaused
состояние как зависимость к useEffect
.
Ну, хорошо , готово.
Но я заметил повторное подключение к серверу WS после каждого нажатия кнопки. Это явно не то, что я хочу.
Моя следующая итерация состояла в том, чтобы использовать два useEffect
s: один для соединения и один для обработки сообщений.
export default function AppWs() {
const [isPaused, setPause] = useState(false);
const [ws, setWs] = useState(null);
useEffect(() => {
const wsClient = new WebSocket('wss://ws.kraken.com/');
wsClient.onopen = () => {
console.log('ws opened');
setWs(wsClient);
};
wsClient.onclose = () => console.log('ws closed');
return () => {
wsClient.close();
}
}, []);
useEffect(() => {
if (!ws) return;
ws.onmessage = e => {
if (isPaused) return;
const message = JSON.parse(e.data);
console.log('e', message);
};
}, [isPaused, ws]);
return (
<div>
<button onClick={() => setPause(!isPaused)}>{isPaused ? 'Resume' : 'Pause'}</button>
</div>
)
}
Это работает, как и ожидалось, но У меня такое чувство, что я что-то упускаю и эту задачу можно решить проще, с одним useEffect
. Пожалуйста, помогите изменить код, чтобы убедить меня, что я правильно использую React-хуки. Спасибо!