【问题标题】:How to display message when user disconnects from chat room in socket.io如何在用户与 socket.io 中的聊天室断开连接时显示消息
【发布时间】:2021-11-14 09:25:47
【问题描述】:

我正在做一个有聊天室的项目。消息传递和加入消息工作正常,但我不知道当有人断开连接时如何显示消息。正如您将在下面的代码中看到的那样,我对 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 没有做任何事情。无论有没有它,代码的工作方式都是一样的。

【问题讨论】:

  • 针对每个socket id,你是否维护了服务器上所有连接用户的列表?还是只是在客户端?

标签: node.js reactjs express socket.io


【解决方案1】:
  1. 在服务器应用程序中,定义一个类似于join 事件的pre_disconnect 事件。
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 状态更新时都会建立并关闭一个新的套接字连接。这意味着当前会话中的消息数量将由套接字连接/断开的数量生成。 From React Docs

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

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

  1. 在 react 应用程序中,使用 usnm 触发 pre_disconnect 事件,然后调用 socketRef.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 条件中。请检查更改。

【讨论】:

  • 先生,我已经在我的代码中进行了您建议的更改,但仍然无法正常工作,实际上它对输出没有任何影响。我已经编辑了问题中的代码,请检查它。同样在您的代码中,您已经在上面的useEffect 中注释了io.connect 部分,所以它抛出了错误,所以我没有执行该步骤。
  • 检查编辑。我认为错误是因为在初始化之前访问了“socketRef.current”。
猜你喜欢
  • 2021-04-07
  • 2016-08-29
  • 2017-03-05
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 2017-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多