首页 > 解决方案 > 如何在用户与 socket.io 中的聊天室断开连接时显示消息

问题描述

我正在做一个有聊天室的项目。消息传递和加入消息工作正常,但我不知道当有人断开连接时如何显示消息。正如您将在下面的代码中看到的,我对 socket.io 了解不多。

(编辑)

服务器代码(Express/Node)

    io.on('connection', socket => {
  socket.on('message', ({ name, message }) => {
    io.emit('message', { name, message })
  })
  socket.on('join' , (name)=>{
    console.log(name);
    socket.broadcast.emit("join" , name.usnm.toUpperCase() + " just joined")
  })
  socket.on('pre_disconnect', (name) => {
    console.log(name);
    socket.broadcast.emit("pre_disconnect" , name.usnm.toUpperCase() + " just left")
  })
})

客户端代码(React.js)

const socketRef = useRef()
useEffect(
    () => {
        socketRef.current = io.connect("http://localhost:4000")
        
        socketRef.current.on("message", ({ name, message }) => {
            setChat([ ...chat, { name, message } ])
        })
        socketRef.current.on("join", (usnm) => {
            setChat([ ...chat, {name:usnm} ])
        })
        socketRef.current.on("pre_disconnect", (usnm) => {
        setChat([ ...chat, {name:usnm} ])
    })
    },
    [ chat ]
)
useEffect(
    () => {
        let usnm = sessionStorage.getItem("User");
        socketRef.current.emit("join" ,{usnm});
        return () => {
      socketRef.current.emit("pre_disconnect" ,{usnm});
      socketRef.current.disconnect()
    }
    },
    [  ]
)

在上面的代码pre_disconnect中没有做任何事情。无论有没有它,代码的工作方式都是一样的。

标签: node.jsreactjsexpresssocket.io

解决方案


  1. 在服务器应用程序中,定义一个pre_disconnect与事件类似的join事件。
io.on('connection', socket => {
  socket.on('message', ({ name, message }) => {
    io.emit('message', { name, message })
  })
  socket.on('join', (name) => {
    console.log(name);
    socket.broadcast.emit("join" , name.usnm.toUpperCase() + " just joined")
  })
  // Fire this before disconnecting the socket
  socket.on('pre_disconnect', (name) => {
    console.log(name);
    socket.broadcast.emit("pre_disconnect" , name.usnm.toUpperCase() + " just left")
  })
})

  1. 在第一个useEffect钩子调用中,每次有chat状态更新时都会建立并关闭一个新的套接字连接。这意味着当前会话中的消息数量将由套接字连接/断开的数量生成。来自 React 文档

效果的默认行为是在每次完成渲染后触发效果。这样,如果其依赖项之一发生更改,则始终会重新创建效果。但是,在某些情况下,这可能有点矫枉过正,例如上一节中的订阅示例。我们不需要在每次更新时都创建一个新订阅,只要源属性发生了变化。要实现这一点,请将第二个参数传递给 useEffect,它是效果所依赖的值数组。

同样,除非您明确需要在每次chat更新时创建和关闭新连接,否则出于性能原因避免使用它。

  1. 在反应应用程序中,在调用之前pre_disconnect使用 , 触发事件并添加类似于.usnmsocketRef.current.disconnect()join
const socketRef = useRef()
useEffect(() => {
    // socketRef.current = io.connect("http://localhost:4000")
    if (socketRef.current) {
        // Add socketRef as dependency and check if socketRef.current exists then continue with listeners
        socketRef.current.on("message", ({ name, message }) => {
            setChat([...chat, { name, message }]);
        });
        socketRef.current.on("join", (usnm) => {
            setChat([...chat, { name: usnm }]);
        });

        // handler for disconnect message
        socketRef.current.on("pre_disconnect", (usnm) => {
            setChat([...chat, { name: usnm }]);
        });
    }
    // return () => socketRef.current.disconnect()
}, [chat, socketRef]);
useEffect(
    () => {
        // Here, creates a socket connection only when component renders the first time. Similar to componentDidMount() in class components
        socketRef.current = io.connect("http://localhost:4000")
        let usnm = sessionStorage.getItem("User");
        socketRef.current.emit("join" ,{usnm});

        // Disconnect the socket when component is to be unmounted from DOM. Similar to componentWillUnmount() in class components
        return () => {
          socketRef.current.emit("pre_disconnect" ,{usnm});
          socketRef.current.disconnect()
        }
    },
    [  ]
)

编辑:

您收到该错误是因为socketRef未初始化。我已添加socketRef为依赖项并将代码包装在if条件中。请检查更改。


推荐阅读