我有两个用户通过加入同一个Socket.io房间而获得私人消息,该房间基于从发送者和接收者ID创建的房间。每次我创建一条消息时,由于状态更改,由于Socket.io发出事件重新渲染,客户端都会重新加入房间,并且将RoomId记录在控制台中。结果,当消息加入同一个会议室时,消息不会通过多个聊天实例进行传输。
const ChatApp = () => {
const [messages, setMessages] = React.useState([]);
const userId = useSelector(state => state.profile.profile._id);
const senderFullName = useSelector(state => state.auth.user.fullname);
const authId = useSelector(state => state.auth.user._id);
const roomId = [authId, userId].sort().join('-');
const ioClient = io.connect("http://localhost:5000");
ioClient.emit('join', {roomid: roomId});
ioClient.emit('connected', {roomid: roomId} );
ioClient.on('message', (msg) => {
const messageObject = {
username: msg.from,
message : msg.body,
timestamp: msg.timestamp
};
addMessage(messageObject);
});
const addMessage = (message) => {
const messagess = [...messages];
messagess.push(message);
setMessages(messagess);
console.log(messagess);
}
const sendHandler = (message) => {
var res = moment().format('MM/DD/YYYY h:mm a').toString();
// Emit the message to the server
ioClient.emit('server:message', {from: senderFullName, body: message, timestamp: res });
}
return (
<div className="landing">
<Container>
<Row className="mt-5">
<Col md={{ span: 8, offset: 2 }}>
<Card style={{ height: "36rem" }} border="dark">
<Messages msgs={messages} />
<Card.Footer>
<ChatInput onSend={sendHandler}>
</ChatInput>
</Card.Footer>
</Card>
</Col>
</Row>
</Container>
</div>
)
};
服务器中使用的api代码
io.sockets.on("connection",function(socket){
// Everytime a client logs in, display a connected message
console.log("Server-Client Connected!");
socket.on('join', function(data) {
socket.join(data.roomid, () => {
//this room id is being console logged every time i send a message
console.log(data.roomid);
});
});
socket.on('connected', function(data) {
//load all messages
console.log('message received');
(async () => {
try {
console.log('searching for Schema');
const conversation = await Conversation.find({roomId: data.roomid}).populate('messages').lean().exec();
const mess = conversation.map();
console.log(mess);
console.log('Schema found');
}
catch (error) {
console.log('Schema being created');
Conversation.create({roomId: data.roomid});
}
})();
});
socket.on('server:message', data => {
socket.emit('message', {from: data.from, body: data.body, timestamp: data.timestamp});
console.log(data.body);
Message.create({from: data.from, body: data.body});
})
});
答案 0 :(得分:1)
您可以将套接字状态上移到父组件,或者将事件初始化移动到在整个应用程序中共享一次的自定义钩子,也可以移到此处的useEffect
钩子,以便仅在初始渲染时运行
最简单的选择也许是后一种选择,您可以像这样包装只想一次编写的代码行:
useEffect(() => {
ioClient.emit('join', {roomid: roomId});
ioClient.emit('connected', {roomid: roomId} );
ioClient.on('message', (msg) => {
const messageObject = {
username: msg.from,
message : msg.body,
timestamp: msg.timestamp
};
addMessage(messageObject);
});
}, []);
最后一个空数组表示它将仅在初始渲染时运行,而不会再次运行,因为它没有依赖性。
更新
您可能会或可能不会遇到关闭或计时问题,但是为了安全起见,将“ addMessage(messageObject);`”行替换为:
setMessages((previousMessages) => [messageObject, ...previousMessages]);
这与addMessage
函数具有相同的作用,但是通过将回调函数传递给setMessages
,可以避免从外部使用状态对象。