我的 React Websocket 为什么一直处于连接状态,直到组件渲染完成?

huangapple go评论60阅读模式
英文:

Why is my React Websocket stuck on connecting until component renders?

问题

In my React component, I have a Websocket that is stuck in a connecting state until my component renders. The code looks as follows:

function MyComponent() {
    const [websocket, setWebsocket] = useState(null);

    useEffect(() => {
        const newWebsocket = new WebSocket(ENDPOINT);
        newWebsocket.onopen = () => console.log('hello there!');
        setWebsocket(newWebsocket);
    }, []);

    useEffect(() => {
        console.log(`readState: ${websocket?.readyState}`);
    }, [websocket?.readyState]);

    const onRender = useCallback(() => {
        if (websocket === null) {
            return;
        }
        websocket.onmessage = () => console.log('received a message!');
    }, [websocket]);

    return (
        (websocket !== null) 
            ? <ChildComponent onRender={onRender} />
            : <div> No Websocket </div>
    );
}

hello there! prints, which shows the WebSocket connection is open, but the useEffect logging readyState only prints CONNECTING.

Does websocket.onmessage have to be defined before the websocket can transition from connecting to open? Or is there some other issue going on?

I expect the websocket to transition from connecting to open without needing ChildComponent to first render. However, what happens now is that I need to define something like

return (
    (websocket?.readyState === WebSocket.CONNECTING || websocket?.readyState === WebSocket.OPEN)
        ? <ChildComponent onRender={onRender} />
        : <div> No WebSocket </div>
);

for the websocket to go from connecting to open. What I'd like to do is define something like this

return (
    (websocket?.readyState === WebSocket.OPEN)
        ? <ChildComponent onRender={onRender} />
        : <div> No WebSocket </div>
);
英文:

In my React component, I have a Websocket that is stuck in a connecting state until my component renders. The code looks as follows:

function MyComponent() {
    const [websocket, setWebsocket] = useState(null);

    useEffect(() =&gt; {
        const newWebsocket = new WebSocket(ENDPOINT);
        newWebsocket.onopen = () =&gt; console.log(&#39;hello there!&#39;);
        setWebsocket(newWebsocket);
    }, []);

    useEffect(() =&gt; {
        console.log(`readState: ${ws?.readyState}`);
    }, [ws?.readyState]};

    const onRender = useCallback(() =&gt; {
        if (websocket === null) {
            return;
        }
        websocket.onmessage = () =&gt; console.log(&#39;received a message!&#39;);
    }, [websocket]);

    return (
        (websocket !== null) 
            ? &lt;ChildComponent onRender={onRender} /&gt;
            : &lt;div&gt; No Websocket &lt;/div&gt;
    );
}

hello there! prints, which shows the WebSocket connection is open, but the useEffect logging readyState only prints CONNECTING.

Does websocket.onmessage have to be defined before the websocket can transition from connecting to open? Or is there some other issue going on?

I expect the websocket to transition from connecting to open without needing ChildComponent to first render. However, what happens now is that I need to define something like

return (
    (websocket?.readyState === WebSocket.CONNECTING || websocket?.readyState === WebSocket.OPEN)
        ? &lt;ChildComponent onRender={onRender} /&gt;
        : &lt;div&gt; No WebSocket &lt;/div&gt;
);

for the websocket to go from connecting to open. What I'd like to do is define something like this

return (
    (websocket?.readyState === WebSocket.OPEN)
        ? &lt;ChildComponent onRender={onRender} /&gt;
        : &lt;div&gt; No WebSocket &lt;/div&gt;
);

答案1

得分: 0

这段代码存在问题,因为对 websocket.readyState 的更新不会触发重新渲染。而对 websocket 状态变量的更新会触发重新渲染,但对 websocket 属性的更新则不会。如果你想要屏幕更新,你可以像这样做:

function MyComponent() {
    const [websocket, setWebsocket] = useState(null);
    const [readyState, setReadyState] = useState(WebSocket.CLOSED);

    useEffect(() => {
        const newWebsocket = new WebSocket(ENDPOINT);
        setReadyState(WebSocket.CONNECTING);
        newWebsocket.onopen = () => setReadyState(WebSocket.OPEN);
        newWebsocket.onclose = () => setReadyState(WebSocket.CLOSED);
        setWebsocket(newWebsocket);
    }, []);

    useEffect(() => {
        console.log(`readyState: ${readyState}`);
    }, [readyState]);

    const onRender = useCallback(() => {
        if (websocket === null) {
            return;
        }
        websocket.onmessage = () => console.log('received a message!');
    }, [websocket]);

    return (
        (readyState === WebSocket.OPEN) 
            ? <ChildComponent onRender={onRender} />
            : <div> No Websocket </div>
    );
}

请注意,这只是代码的翻译,不包含任何其他信息。

英文:

This doesn't work because updates to websocket.readyState will not trigger a re-render. While updates to the state variable websocket will trigger an update, updates of the properties of websocket will not. If you want the screen to update, you can do something like this:

function MyComponent() {
    const [websocket, setWebsocket] = useState(null);
    const [readyState, setReadyState] = useState(WebSocket.CLOSED);

    useEffect(() =&gt; {
        const newWebsocket = new WebSocket(ENDPOINT);
        setReadyState(WebSocket.CONNECTING);
        newWebsocket.onopen = () =&gt; setReadyState(WebSocket.OPEN);
        newWebsocket.onclose = () =&gt; setReadyState(WebSocket.CLOSED);
        setWebsocket(newWebsocket);
    }, []);

    useEffect(() =&gt; {
        console.log(`readyState: ${readyState}`);
    }, [readyState]};

    const onRender = useCallback(() =&gt; {
        if (websocket === null) {
            return;
        }
        websocket.onmessage = () =&gt; console.log(&#39;received a message!&#39;);
    }, [websocket]);

    return (
        (readyState === WebSocket.OPEN) 
            ? &lt;ChildComponent onRender={onRender} /&gt;
            : &lt;div&gt; No Websocket &lt;/div&gt;
    );
}

huangapple
  • 本文由 发表于 2023年5月25日 21:41:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76332962.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定