Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

1.3K
Vistas
El oyente socket.io del servidor se dispara dos veces sin razón aparente

Estoy creando una aplicación con una función de chat usando express.js, react.js y socket.io. Aquí hay una versión mínima con el error reproducido en Github .

El problema es que el socket.on() del servidor siempre se dispara dos veces, sin ninguna razón aparente para mí.

Por lo que puedo decir, el cliente solo envía un único .emit , pero el .on del servidor siempre se dispara dos veces (y estoy bastante seguro de que el controlador de eventos no está vinculado dos veces), independientemente de cuántos clientes estén conectados, o de hecho, cómo he refactorizado el código.

El formulario del cliente que envía (entrada + botón) agrega el mensaje a su lista de mensajes locales y luego envía MESSAGE_NEW al reductor.

Aquí está primero el archivo Socket.js .

 import React from 'react' import socketio from 'socket.io-client' export const socket = socketio.connect('ws://localhost:3001') export const SocketContext = React.createContext()

Y aquí está el código del controlador de envío de Chat.js (esto parece funcionar correctamente, se envía solo una vez):

 const handleSubmit = e => { e.preventDefault() if (message === '') return setMessages(messages => [...messages, message]) dispatch({ type: 'MESSAGE_NEW', payload: message }) setMessage('') }

Aquí está /Reducer.js , que .emit es la señal (también parece funcionar bien, disparando solo una vez).

 import { useContext } from 'react' import { SocketContext } from './Socket' export default function Reducer(state, action) { const socket = useContext(SocketContext) switch (action.type) { case 'MESSAGE_NEW': // this only fires once, as it should console.log('emitting socket') socket.emit('message:new', action.payload) break default: return state } }

Pero aquí está el bit relevante de /server/index.js , aquí es donde las cosas van mal. No importa lo que haya intentado, el .on siempre se dispara dos veces.

 io.on('connection', socket => { console.log('New client connected:', socket.id) socket.on('message:new', message => { // this always fires twice, i do not understand why console.log('message:new: ', message, socket.id) socket.broadcast.emit('message:new', message) }) })

Actualización: descubrí que mover socket.emit de Reducer.js a handleSubmit en Chat.js hace que funcione bien. No entiendo por qué, ya que el Reductor no dispara dos veces.

over 4 years ago · Santiago Trujillo
4 Respuestas
Responde la pregunta

0

En https://github.com/Heilemann/sockettest/blob/c1df22349ac1877ed625a01b14f48730b7af122d/client/src/Chat.jsx#L14-L22 , agrega un detector de eventos y luego intenta eliminarlo nuevamente. Pero como escribes la función del controlador

 message => { setMessages([...messages, message]) }

cada vez, la eliminación no tiene efecto, ya que el controlador que se eliminará no es idéntico al que agregó. Debe asignar la función de controlador a una variable y usar esa variable en .on y .off .

Incluso si esto no soluciona el problema, vale la pena hacerlo.

over 4 years ago · Santiago Trujillo Denunciar

0

Su componente se está renderizando dos veces, llamando al socket dos veces y dando dos mensajes de conexión.

Asegúrese de que se renderice una vez usando su useEffect como este

En tu chat.js importa el socket.io

 import socketio from 'socket.io-client' let socket useEffect(() => { socket = socketio.connect('ws://localhost:3001') return () => { socket.off('message:new', listener) } },[])

En su controlador de envío

 const handleSubmit = e => { e.preventDefault() if (message === '') return setMessages(messages => [...messages, message]) socket.emit('message:new', message) //dispatch({ type: 'MESSAGE_NEW', payload: message }) setMessage('') }

Pasar una matriz vacía como segundo argumento significa que useEffect solo se llamará una vez. La conclusión es asegurarse de que el cliente socket.io se llame una vez. props y los cambios de estado hacen que el componente se vuelva a renderizar, lo que a su vez hace que el zócalo se conecte varias veces. Puedes explorar otros patrones más limpios. Sin embargo, esto es lo que tienes que hacer.

over 4 years ago · Santiago Trujillo Denunciar

0

Según la documentación de React en modo estricto :

El modo estricto no puede detectar automáticamente los efectos secundarios, pero puede ayudarlo a detectarlos haciéndolos un poco más deterministas. Esto se hace mediante una doble invocación intencional de las siguientes funciones:

  • Métodos constructor de componentes de clase, render y shouldComponentUpdate
  • Componente de clase método estático getDerivedStateFromProps
  • Cuerpos de componentes de función
  • Funciones de actualización de estado (el primer argumento de setState )
  • Funciones pasadas a useState , useMemo o useReducer

Observe la última línea: las funciones que se pasan a useReducer se invocarán dos veces; es por eso que su mensaje se envía dos veces. Puede confirmar esto actualizando su reductor así:

 case "MESSAGE_NEW": alert("I'm running");

Notará que esta alerta aparece dos veces, gracias a React.StrictMode .

Si elimina el envoltorio <React.StrictMode> en src/App.js , el mensaje de test ya no se repetirá; sin embargo, no está solucionando el problema subyacente aquí.

El problema subyacente es que está haciendo que su reductor (que debería ser puro) realice un efecto secundario impuro (en este caso, enviando un mensaje a través de un websocket). Además, la función reducer también tiene una llamada useContext ; esto tampoco es operativo desde la perspectiva de React y no es una buena práctica.

Como se ha encontrado en su pregunta, simplemente mueva el socket.emit a su handleSubmit y debería estar listo para comenzar. Alternativamente, puede considerar una configuración más sofisticada si desea ir por la ruta reductora; algunas configuraciones populares incluyen Redux + Redux Thunk o Redux + Redux Saga. Su experiencia puede ser diferente.

over 4 years ago · Santiago Trujillo Denunciar

0

Depuré su código y encontré el problema con el reductor activándose dos veces.

La solución es eliminar las etiquetas <React.StrictMode> alrededor de la etiqueta de su aplicación en index.js .

Más información sobre StrictMode : https://reactjs.org/docs/strict-mode.html

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda