【发布时间】:2020-05-25 22:05:10
【问题描述】:
我需要连接到 WebSockets 服务器并记录它的消息。使用 React 类组件,我会将这个逻辑放在 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>
)
}
我向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 服务器。这显然不是我想要的。
我的下一个迭代是使用两个useEffects:一个用于连接,一个用于消息处理。
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 钩子。谢谢!
【问题讨论】:
标签: javascript reactjs websocket react-hooks