Estoy usando websocket en reaccionar. Este es el código del componente:
import React, { useState, useEffect } from "react"; export default function Component(props) { const [socket, setSocket] = useState(); const parseMessage = (msg) => { if (msg[0] !== "R") sendMessage("123"); // ignore the very first message from the socket. }; const sendMessage = (msg) => socket.send(msg); // error at this line useEffect(() => { const socket = new WebSocket("wss://ws.ifelse.io/"); socket.addEventListener("message", ({ data }) => { if (socket) parseMessage(data); }); setSocket(socket); }, []); const sendMsg = () => { socket.send("test"); }; return <button onClick={() => sendMsg("clicked")}>send msg</button>; } Recibo este error: TypeError: Cannot read properties of undefined (reading 'send') en la línea marcada. El WebSocket es solo un servidor de eco, devuelve lo mismo que le envías.
Si socket.send en un bloque try-catch, aún puedo enviar y recibir mensajes del WebSocket usando el botón, pero el error aún ocurre en esa línea en sendMessage .
Está claro que la variable de socket no está indefinida, ya que puedo enviar y recibir mensajes antes y después de que ocurra el error.
Entonces, mi pregunta es por qué la variable de socket no está definida solo durante el breve período después de recibir un mensaje, y cuál es la solución para este problema.
Una mejor solución sería inicializar el zócalo afuera
import React, { useState, useEffect } from "react"; const socket = new WebSocket("wss://ws.ifelse.io/") export default function Component(props) { const ws = useRef(socket) useEffect(() => { ws.current?.addEventListener("message", ({ data }) => { parseMessage(data); }); return () => { ws.current?.removeAllListeners() } }, []) const parseMessage = (msg) => { if (msg[0] !== "R") sendMessage("123"); // ignore the very first message from the socket. }; const sendMessage = (msg) => ws.current?.send(msg); const sendMsg = () => { ws.current?.send("test"); }; return <button onClick={() => sendMsg("clicked")}>send msg</button>; }El useEffect se ejecuta solo una vez y en ese momento el socket aún no está definido. La función sendMessage hace referencia a un socket indefinido cuando se ejecuta el efecto. Cuando el socket se configura usando setSocket , el componente se volverá a representar, pero la nueva instancia de sendMessage (que ahora hace referencia al socket existente) nunca se usará, porque el efecto no volverá a ejecutarse.
Es mejor usar ref en este caso.
export default function Component(props) { const socket = useRef(); const sendMessage = (msg) => socket.current.send(msg); useEffect(() => { socket.current = new WebSocket("wss://ws.ifelse.io/"); socket.current.addEventListener("message", ({ data }) => { parseMessage(data); }); return () => { ... release resources here } }, []); ... }Cuando usa useState , crea una variable de estado con una función de estado de actualización. También proporciona el valor inicial de la variable de estado en useState(initialState) .
En su caso, no está pasando nada (es decir, le está diciendo a React que no está undefined , por eso en esta línea:
const sendMessage = (msg) => socket.send(msg); // error at this line su código no puede usar socket.send porque socket no está undefined .
Su useEffect se ejecuta después de la función de devolución y luego se crea la instancia del socket y se establece en la variable de estado del socket.
Debe asegurarse de que solo está enviando un mensaje a través del socket después de que se crea el socket.
Para obtener más información sobre useEffect , puede leer esta publicación: https://jayendra.xyz/2019/06/17/how-useeffect-works/