【问题标题】:State resets when receiving socket message收到套接字消息时状态重置
【发布时间】:2023-02-11 13:48:30
【问题描述】:

我正在尝试使用 Next、Express 和 Socket.io 创建一个聊天应用程序。 我面临的问题如下: 我有 2 个浏览器,我从第一个浏览器发送一条消息,然后在第二个浏览器中看到它,但是如果我发送另一条消息,管理消息的状态(字符串数组)每次都会重置,here's an example

后端:

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

前端

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

【问题讨论】:

    标签: reactjs express websocket socket.io next.js


    【解决方案1】:

    由于我不熟悉使用 websockets 以及如何在 React 中实现它,所以我尝试了所有我能想到的方法来解决它,所以最后我最终取出了 socket.on("receive_message"...socket.on("receive_message"... 现在它可以工作了,不要不知道这是否是正确的解决方案,但它确实有效。

    现在前端看起来像:

    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
    

    【讨论】:

    • 如果您注释掉更新代码中显示的接收消息,您将不再有响应后端发出的事件处理程序。我目前遇到了同样的问题。似乎您的状态将不再重置,而且您也无法再在前端收到消息。
    【解决方案2】:

    您可以通过使用先前的状态来执行状态更新,以保留先前的状态值并避免状态重置。创建一个在收到消息时更新状态变量的函数。在 useEffect 中调用此函数,将套接字的值保留为依赖项,以便每次套接字发出事件时都会更新状态

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-04
      • 2016-02-28
      相关资源
      最近更新 更多