英文:
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(() => {
const newWebsocket = new WebSocket(ENDPOINT);
newWebsocket.onopen = () => console.log('hello there!');
setWebsocket(newWebsocket);
}, []);
useEffect(() => {
console.log(`readState: ${ws?.readyState}`);
}, [ws?.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>
);
答案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(() => {
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>
);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论