使用mern-stack和socket.io的聊天应用程序在发送了20多条消息后速度变慢



我正在使用MERN堆栈和socket.io构建一个实时聊天应用程序。在发送了大约20条消息后,该应用程序变得很慢,当其他用户只有在收到发送的消息后才发送另一条消息时,用户无法编写和发送消息。这是我的聊天组件

import React, {useEffect, useRef, useState} from 'react';
import Messages from "../Messages/Messages";
import axios from 'axios';
import io from "socket.io-client";
const socket = io('http://localhost:5000/')
function Chat(props) {
const [messages, setMessages] = useState([])
const [input, setInput] = useState("")
useEffect(() => {
axios.get("http://localhost:5000/")
.then((res) => {
setMessages(res.data)
})

return () => {
socket.disconnect();
}
}, [])
useEffect(() => {
socket.on('msgSent', (data) => {
setMessages([...messages, data])
})
}, [messages])
const renderMessages = () => {
return (
messages.map( (message) => {
return (
<Messages key={message._id} sender={message.sender.firstName.concat(message.sender.lastName)}
messageText={message.messageText}
/>
)
})
)
}
const sendMessage = (e) => {
e.preventDefault()
const message = {
messageText: input,
}
axios.post("http://localhost:5000/", message)
.then(res => {
setMessages([...messages, res.data])
socket.emit('msgSent', res.data)
})         
}
return (       
{renderMessages()}
<form onSubmit={(e) => sendMessage(e)}>
<input type="text" placeholder="type a message" value={input}
onChange={(e) => setInput(e.target.value)}/>
<button type="submit"></button>
</form>                
);
}
export default Chat;

这是我的服务器端代码

const express = require("express")
const app = express()
const mongoose = require('mongoose')
const homeRoot = require("./Routes/homeRoot")
const http = require('http').Server(app);
const io = require('socket.io')(http)    
//listening
http.listen(5000, () => {
console.log("hello from server")
})
//Routes
app.use("/", homeRoot)
//socket
io.on('connection', (socket) => {
socket.on('msgSent',(data)=>{
socket.broadcast.emit('msgSent',data)
})
});
//Db connection
mongoose.connect("mongodb+srv://@cluster0.agiog.mongodb.net/myFirstDatabase?retryWrites=true&w=majority")

这是homeRoot,我在这里获取消息

const express = require("express")
const Router = express.Router()
const Messages = require("../Models/messageModel")
const Users = require("../Models/userModel")
const auth = require("../auth")
Router.get("/",auth,async(req,res)=>{
try {
const messages = await Messages.find().populate("sender","firstName lastName")
res.status(200).send(messages)
}catch (e) {
res.status(404).send("messages not found")
}
})
Router.post("/",auth,async(req,res)=>{
const user = await Users.findOne({_id:req.userId})
const message = new Messages({...req.body,sender:user})
try {
const savedMessage = await message.save()
res.status(201).send(savedMessage)
}catch (e) {
res.status(404).send("error occured")
}
})
module.exports = Router
useEffect(() => {
socket.on('msgSent', (data) => {
setMessages([...messages, data])
})
return{
socket.off("msgSent");
}
}, [messages])

您需要像上面例子中这样使用socket.off((。

Yadnesh给出的答案有一个小陷阱。让我解释一下。

首先让我们看看为什么您的代码有问题


您已经将socket.on监听器直接放在组件中,而不是放在任何钩子中。这意味着每次您的组件重新呈现一个新的套接字时,都会创建一个监听器。
  • 您的组件已安装->您将有一个套接字。on侦听器
  • 您收到第一条消息->上一个侦听器仍然存在,但由于组件重新呈现,将创建一个新的侦听器
  • 您收到第二条消息->前两个监听器加在一起,现在总共有4个监听器

这种模式还在继续。。

你可能会想使用下面给出的代码,但这是错误的方法

useEffect(() => {
socket.on('msgSent', (data) => {
setMessages([...messages, data])
});
return () => {
socket.off("msgSend");
};
}, [messages]);

使用[messageList]作为第二个参数来使用效果

问题是你不想每次更新messageList时都创建一个新的socket.io侦听器。在组件的生命周期中,您应该始终只为一个事件创建一个侦听器。因为一旦创建了socket.on侦听器,它在侦听该事件的第一次发生后就不会被破坏,它只是再次侦听该事件。

因此,这样的监听器必须创建一次。在您的情况下,它应该在组件装载时创建。

因此,使用[],空列表作为第二个参数来使用Effect。这个钩子相当于componentDidMount。

正确的代码

useEffect(() => {
socket.on('msgSent', (data) => {
setMessages([...messages, data])
});
return () => {
socket.off("msgSend");
};
}, []);

最新更新