简体   繁体   English

状态在use内部不变

[英]State doesn't change inside useEffect

I'm trying to use websocket with hooks and starting it on useEffect. 我正在尝试将Websocket与钩子一起使用,并在useEffect上启动它。 But the states is always the initial for the websocket. 但是状态始终是websocket的初始状态。

I know that it happens because useEffect creates a closure, but I didn't find a workaround. 我知道发生这种情况是因为useEffect创建了一个闭合,但是我没有找到解决方法。

I simplified my code to make easily understandable. 我简化了代码,使其易于理解。 I need to make decisions according to activeContracts, but it doesn't change. 我需要根据activeContracts做出决定,但它不会改变。 I tried not to use ws as a state, but then it is lost on new renderings. 我尝试不将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>
    );
}

Is there anyway to the websocket notice changes on states? 无论如何,websocket是否会通知状态变化? Should I initialize the websocket in another way or don't keep it as an state? 我应该以其他方式初始化websocket还是不将其保持为状态?

Update: 更新:

I added a useEffect tracking activeContracts and update onopen and onmessage and worked. 我添加了一个useEffect跟踪activeContracts并更新onopen和onmessage并正常工作。 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],
);

That's because useState runs only once when component initialises, due to the array argument being empty. 这是因为useState在数组初始化时仅在组件初始化时运行一次。 You need to track activeContracts in that array, but because activeContracts is array itself you'll need to use some kind of deep compare function for it: https://stackoverflow.com/a/54096391/4468021 您需要跟踪该数组中的activeContracts ,但是由于activeContracts是数组本身,因此您需要为其使用某种深度比较功能: https : //stackoverflow.com/a/54096391/4468021

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM