#StackBounty: #reactjs #express #socket.io Server's socket.io listener fires twice for no apparent reason

Bounty: 100

I’m building an app with a chat feature using express.js, react.js and socket.io. Here is a minimal version with the bug reproduced on Github.

The problem is the server’s socket.on() always fires twice, for no reason that is apparent to me.

As far as I can tell the client only ever sends a single .emit, but the server’s .on always fires twice (and I’m fairly certain that event handler isn’t bound twice), regardless of how many clients are connected, or indeed how I’ve refactored the code.

The sending client’s form (input + button) appends the message to its local messages list and then dispatches MESSAGE_NEW to the reducer.

Here’s first the Socket.js file.

import React from 'react'
import socketio from 'socket.io-client'

export const socket = socketio.connect('ws://localhost:3001')
export const SocketContext = React.createContext()

And here is the submit handler code from Chat.js (this seems to work correctly, dispatching just once):

const handleSubmit = e => {
  e.preventDefault()

  if (message === '') return

  setMessages(messages => [...messages, message])
  dispatch({ type: 'MESSAGE_NEW', payload: message })
  setMessage('')
}

Here’s /Reducer.js, which .emit‘s the signal (also seems to work fine, firing just once).

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
  }
}

But here is the relevant bit from /server/index.js, this is where things go wrong. No matter what I’ve tried, the .on always fires twice.

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)
  })
})

Update: I found out that moving the socket.emit from Reducer.js to handleSubmit in Chat.js makes it work just fine. I don’t understand why since the Reducer doesn’t fire twice.


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.