I'm trying to use websocket with hooks and starting it on useEffect. But the states is always the initial for the websocket.
I know that it happens because useEffect creates a closure, but I didn't find a workaround.
I simplified my code to make easily understandable. I need to make decisions according to activeContracts, but it doesn't change. I tried not to use ws as a state, but then it is lost on new renderings.
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>
);
}
Is there anyway to the websocket notice changes on states? Should I initialize the websocket in another way or don't keep it as an state?
Update:
I added a useEffect tracking activeContracts and update onopen and onmessage and worked. Something like this:
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],
);