我正在尝试使用带有钩子的websocket并在useEffect上启动它。但是状态始终是 websocket 的首字母。
我知道发生这种情况是因为 useEffect 创建了一个闭包,但我没有找到解决方法。
我简化了我的代码,使其易于理解。我需要根据活动合同做出决定,但它不会改变。我尽量不使用ws作为状态,但后来它在新的渲染中丢失了。
function Bitstamp() {
const [activeContracts, setActiveContracts] = useState(["btcusd"]);
const [ws, setWs] = useState();
useEffect(
() => {
let newWs = new WebSocket("wss://ws.bitstamp.net");
newWs.onopen = function () {
activeContracts.map(contract => newWs.send({
"event": "bts:subscribe",
"data": {
"channel": "order_book_btcusd"
}
}));
};
newWs.onmessage = function (evt) {
console.log(activeContracts);
};
setWs(newWs);
},
[],
);
const handleContractChange = val => {
setActiveContracts(val);
};
return (
<ToggleButtonGroup vertical type="checkbox" value={activeContracts}
onChange={handleContractChange}>
<ToggleButton
value="btcusd">"btcusd"</ToggleButton>
)}
<ToggleButton
value="btceur">"btceur"</ToggleButton>
)}
</ToggleButtonGroup>
);
}
websocket 通知的状态是否有任何变化?我应该以其他方式初始化 websocket 还是不将其保留为状态?
更新:
我添加了一个useEffect跟踪活动合同,并在打开和消息上更新并工作。像这样:
useEffect(
() => {
setWs(ws => {
ws.onopen = function () {
activeContracts.map(contract => newWs.send({
"event": "bts:subscribe",
"data": {
"channel": "order_book_btcusd"
}
}));
};
ws.onmessage = function (evt) {
console.log(activeContracts);
};
return ws;
})
},
[activeContracts],
);
这是因为useState
在组件初始化时只运行一次,因为数组参数为空。您需要跟踪该数组中的activeContracts
,但由于activeContracts
数组本身,您需要为其使用某种深度比较函数:https://stackoverflow.com/a/54096391/4468021