System reboots upon socket message reception

I am currently working on developing a chat application using Next, Express, and Socket.io. I have encountered an issue where the state managing the messages in the chat resets every time a new message is sent from one browser to another. You can see an example of this here.

Backend:

import express from 'express'
import http from 'http'
import { Server } from 'socket.io'
import cors from 'cors'

const PORT = 3001
const app = express()
const server = http.createServer(app)
const io = new Server(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"],
  }
})

app.use(express.json())
app.use(cors())

io.on("connection", (socket) => {
  console.log(`User connected: ${socket.id}`)

  socket.on("join_chat", (data) => {
    socket.join(data)
  })

  socket.on("send_message", (data) => {
    console.log(`Mensaje recibido: ${JSON.stringify(data)}`)
    socket.to(data.chat).emit("receive_message", data)
  })
})

server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})

Frontend

import io from 'socket.io-client'
import { useEffect, useState } from 'react'

const socket = io.connect("http://localhost:3001")

export default function Home() {
  const [chat, setChat] = useState("")
  const [message, setMessage] = useState("")
  const [messages, setMessages] = useState([])

  const joinChat = () => {
    if(chat)
      socket.emit("join_chat", chat)
  }

  const addMessage = (newMessage) => {
    setMessages(() => [...messages, newMessage])
  }

  const sendMessage = () => {
    socket.emit("send_message", {
      message,
      chat,
    })
    addMessage(message)
  }
  
  useEffect(() => {
    socket.on("receive_message", (data) => {
      addMessage(data.message)
    })
  }, [])

  return (
    <div>
      <input type="text"
        value={chat}
        placeholder="Chat room number"
        onChange={(e) => setChat(e.target.value)}
      />
      <button
        onClick={() => joinChat()}
      >Click</button>

      <input type="text"
        value={message}
        placeholder="Message"
        onChange={(e) => setMessage(e.target.value)}
      />
      <button
        onClick={() => sendMessage()}
      >Click</button>

      <h1>Received messages</h1>
      {messages.length > 0 && messages.map((message, index) => 
        <li key={index}>{message}</li>
      )}
    </div>
  )
}

Answer №1

Exploring websockets and their integration in React was a new experience for me. I tried various approaches to find a solution, eventually removing the

socket.on("receive_message"...
from the useEffect did the trick. Although I'm not sure if this is the best approach, it resolved the issue.

My updated frontend code now looks like this:

import io from 'socket.io-client'
import { useEffect, useState } from 'react'

const socket = io.connect("http://localhost:3001")

const Home = () => {
  const [chat, setChat] = useState("")
  const [message, setMessage] = useState("")
  const [messages, setMessages] = useState([])

  const joinChat = () => {
    if(chat)
      socket.emit("join_chat", chat)
  }

  const addMessage = (newMessage) => {
    setMessages(() => [...messages, newMessage])
  }

  const sendMessage = () => {
    socket.emit("send_message", {
      message,
      chat,
    })
    addMessage(message)
  }
  
  // useEffect(() => {
    socket.on("receive_message", (data) => {
      addMessage(data.message)
    })
  // }, [])

  return (
    <div>
      <input type="text"
        value={chat}
        placeholder="Chat room number"
        onChange={(e) => setChat(e.target.value)}
      />
      <button
        onClick={() => joinChat()}
      >Click</button>

      <input type="text"
        value={message}
        placeholder="Message"
        onChange={(e) => setMessage(e.target.value)}
      />
      <button
        onClick={() => sendMessage()}
      >Click</button>

      <h1>Received messages</h1>
      {messages.length > 0 && messages.map((message, index) => 
        <li key={index}>{message}</li>
      )}
    </div>
  )
}

export default Home

Answer №2

To avoid resetting the state, you can update it using the previous state value. Simply create a function that updates the state variable when receiving a message. This function should be called within useEffect, with the socket value as a dependency to ensure that the state gets updated whenever an event is emitted by the socket.

function handleMessage() {
    if (socket) {
        socket.on(events.RECEIVE_MESSAGE, (data) => {
            setMessageList((prev) => [...prev, data]);
        });
    }
}

useEffect(() => {
    handleMessage();
}, [socket]);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I'm seeing a message in the console that says "Form submission canceled because the form is not connected." Any idea why this is happening?

For the life of me, I can't figure out why this code refuses to run the handleSubmit function. Essentially, the form is supposed to take an input and execute the handleSubmit function upon submission. This function then makes a POST request to an API ...

Is it possible for a JWT generated using RS256 to be decoded on the jwt.io platform?

After setting up my first Express server and implementing user authentication with jwt, I'm now searching for a method to encrypt the jwt in order to prevent users from viewing the payload on the website. I am curious if anyone is aware of an encryp ...

The JavaScript fetch API failed to receive a response after sending data via a 'POST' request to a Django server

Currently, I am in the process of developing a poll application that utilizes both Django and React. My approach involves using the fetch API to send POST requests to my Django server and receive detailed information in return for further processing. For a ...

Error: Unable to modify the value of a protected property '0' in the object 'Array'

I am facing a challenging issue with implementing a Material UI slider in conjunction with Redux. Below is the code for the slider component: import { Slider } from '@material-ui/core' const RangeSlider = ({handleRange, range}) => { ...

Error: Unable to access the 'version' property of null

Having trouble installing any software on my computer, I've attempted various solutions suggested here but none have been successful. $ npm install axios npm ERR! Cannot read property '**version**' of null npm ERR! A complete log of this ru ...

What steps should be taken to validate a condition prior to launching a NextJS application?

In my NextJS project (version 13.2.4), I usually start the app by running: npm run dev But there's a new requirement where I need to check for a specific condition before starting the app. If this condition is not met, the app should exit. The condi ...

What are the steps to displaying Jade in an Electron application?

With Express, you can easily establish the view engine as Jade by using the following code snippet: app.set('view engine', 'jade'); This enables Express to parse and deliver compiled HTML from Jade files directly. But how can this be ...

Converting hexadecimal to binary using Javascript or Typescript before writing a file on an Android or iOS device

Hey everyone! I'm facing a puzzling issue and I can't seem to figure out why it's happening. I need to download a file that is stored in hex format, so I have to first read it as hex, convert it to binary, and then write it onto an Android/ ...

What is the best way to show the user profile on a Forum?

I am struggling to figure out how to display the username of a user on my forum page. I currently only have access to the user's ID and need help in extracting their name instead. It seems that I lack knowledge about mongoose and could really benefit ...

Limiting the size of image uploads in AWS S3

Currently, I am attempting to go through the steps outlined in this repo, which involves utilizing nextjs and AWS S3 for image uploading. However, one thing that is puzzling me is the limitation of 1MB on image sizes. I'm curious as to why this restri ...

Move information from one webpage to a different page

After developing a site using NextJs, I successfully integrated Discord login functionality and was able to retrieve the user's guilds in the oauth file. Now, I am looking to send this list of guilds (in JSON format) to my dashboard page. In the oau ...

What are the steps to deploy a React, Next.js, and Express.js application on Netlify?

I am currently in the process of deploying my application to Netlify, featuring a combination of React, Next.js, and Express.js. While there are no errors showing up in the Netlify console, unfortunately, the site is not live as expected. https://i.stack ...

Guide to activating the isActive status on a live link within a map iteration utilizing the NEXTUI navigation bar

Check out the new NEXTUI navbar I'm using: I am having trouble setting the isActive property on the active link in my NavBar component in Next.js. I couldn't find much help on Google, so I'm hoping someone here has experience with this or k ...

What is the purpose of the Express 4 namespace parameter?

Having worked extensively with Express 4, I recently attempted to implement a namespaced route with a parameter. This would involve routes like: /:username/shows /:username/shows/:showname/episodes I figured this scenario was ideal for express namespacin ...

Turn off the authentication middleware for a particular HTTP method on a specific endpoint

Currently, I am using Express/Node and have developed authentication middleware to validate JWT on each request. My requirement is to disable this middleware for a specific route (POST '/api/user/') while keeping it active for another route (GET ...

Is it possible to incorporate a next.js image onto the background design?

I've encountered an issue while attempting to create a fixed background image with a parallax effect using Tailwind CSS and Next.js Image. If you need to see an example of this in action, check out this Template Monster theme. Here's the code s ...

Step-by-step guide on invoking a recursive function asynchronously in JavaScript

As I delved into the realm of creating a unique Omegle clone using Node.js and Socket.io for educational purposes, I encountered a challenge that has left me scratching my head. The socket ID of clients along with their interests are stored in an array of ...

What is the syntax for utilizing cookies within the `getServerSideProps` function in Next.js?

I am struggling to pass the current language to an endpoint. Despite attempting to retrieve the language from a Cookie, I keep getting undefined within the getServerSideProps function. export async function getServerSideProps(context) { const lang = aw ...

Next.js is like Gatsby but with the power of GraphQL

I'm curious if it's possible to set up GraphQL in Next.js similar to how it's done in Gatsby, allowing me to query pages and retrieve data from them. Are there any plugins available for Next.js that work like Gatsby-file-source and gatsby-ma ...

React component allowing for the reuse of avatars

As a novice in React, I've encountered a challenge. My goal is to develop a simple reusable component using MUI. Specifically, I aim to create an avatar component that can be easily customized with different images when called upon. I want the flexibi ...