Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

1.3K
Views
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 answers
Answer question

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 Report

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 Report

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!