插座.每次新用户加入房间时,IO将创建2个套接字IDS,而不是1个



我正在创建一个协作反应应用程序,在每次新用户加入房间时,套接字io为每个用户生成2个id,我遵循文档代码,以同样的方式,我不确定为什么会发生这种情况,下面是服务器端代码(server.js)的片段。

const cors = require('cors');
const axios = require('axios');
const {Server} = require('socket.io');
const http = require('http');
const ACTIONS = require('../src/Actions');
const app = express();  // Create an instance of express
const server = http.createServer(app)  // Create an instance of http server
const io = new Server(server); // Create an instance of socket.io server

// Storing a client list
const clients = new Map();

// Switching on the server socket to listen for connections
io.on('connection', (socket) => {
const clientSocketId = socket.id;   

console.log(clientSocketId+' connected');

socket.on(ACTIONS.JOIN,({roomId,username})=>{
console.log(roomId,username)
clients.set(socket.id,{
roomId,
username,
socketId: socket.id,
})
socket.join(roomId);
const clientlist = Array.from(clients.values())
clientlist.forEach(client=>{
io.to(client.socketId).emit(ACTIONS.JOINED,{
clientlist,
username,
socketId: socket.id,
})
})
})
// The server is listening to two events Code Change and Code Sync
// Code Change is emitted when the user changes the code
// Code Sync is called when the user joins the room to sync the previously typed code
socket.on(ACTIONS.CODE_CHANGE, ({ roomId, code }) => {
socket.in(roomId).emit(ACTIONS.CODE_CHANGE, { code });
});
socket.on(ACTIONS.SYNC_CODE, ({ socketId, code }) => {
io.to(socketId).emit(ACTIONS.CODE_CHANGE, { code });
});

// Disconnecting the current socket
socket.on('disconnecting',()=>{
console.log(clientSocketId+' disconnected')
// Getting the list of all the present rooms
const rooms = Object.keys(socket.rooms);
rooms.forEach(roomId=>{  
socket.in(roomId).emit(ACTIONS.DISCONNECTED,{
socketId: socket.id,
username: clients.get(socket.id).username,
})
})
clients.delete(socket.id);
socket.leave();
})

})
const PORT = process.env.SERVER_PORT || 5000;
server.listen(PORT,()=>{console.log('Listening on  '+PORT)});
下面是我如何在客户端初始化套接字

export const initSocket = async () => {
const options =  {
transports: ['websocket'],
reconnection: true,
reconnectionAttempts: 'Infinity',
forceNew: true,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
timeout: 10000,
autoConnect: true,
secure: true,
}
const socket = io(process.env.REACT_APP_SERVER_URL,options)
return socket
}

在我的Dashboard.js中,我调用了UseEffect

中的init函数
React.useEffect(()=>{
// As the user joins the room we initialize the client socket which connects to the server
const init = async () => {
socketRef.current = await initSocket(); 
// Handling connection errors
socketRef.current.on('connect_error',(err)=>handleError(err))
socketRef.current.on('connect_failed',(err)=>handleError(err))
const handleError = (err)=>{
console.log(err)
toast({
title: 'Error connecting to the server',
status: 'error',
duration: 9000,
isClosable: true,
})
reactNavigater('/')
}
socketRef.current.emit(ACTIONS.JOIN,{
roomId: roomId,
username: location.state?.username,
});
// Listening for joined event when a even user joins
socketRef.current.on(ACTIONS.JOINED,({clientlist,username,socketId})=>{
if(username !== location.state?.username){
toast({
title: `${username} has joined the room`,
status: 'success',
duration: 9000,
isClosable: true,
})
}
setClientlist(clientlist)
socketRef.current.emit(ACTIONS.SYNC_CODE, {
socketId: socketRef.current.id,
code: codeRef.current,
});
})
// Listening for disconnected event when a even user disconnects
socketRef.current.on(ACTIONS.DISCONNECTED,({socketId,username})=>{
toast({
title: `${username} has disconnected`,
status: 'warning',
duration: 9000,
isClosable: true,
})
// Filter the clientlist to remove the disconnected client
setClientlist(Clientlist.filter(client=>client.socketId !== socketId))
}
)
}
init()
// Here we have multiple listeners, so we have to remove them when the component unmounts
return ()=>{
if(socketRef.current){
socketRef.current.disconnect()
socketRef.current.off(ACTIONS.JOINED)
socketRef.current.off(ACTIONS.DISCONNECTED)
}
}
},[])

如有任何帮助,不胜感激

如果你有严格模式,默认情况下,那么useEffect被调用两次(从React 18)。你的连接被创建了两次。当每个连接生成新的Id时,你会得到两个Id。

https://stackoverflow.com/a/72238236/8522881

我的React组件渲染两次,因为严格模式

您可以直接包装套接字。在io实例中使用useRef,以便在重新渲染之间保持相同的值,例如:

import React from 'react'
function MyComponent() {
const socket = React.useRef(null)

React.useEffect(() => {
if(!socket.current) {
socket.current = io('ws://my-url/');
}
}, [])

// now you can use socket.current and ensure you aways will have only one instance

return (
<p>hello</p>
)
}

最新更新