繁体   English   中英

使用 React 和 Socket.io 的聊天应用程序在发送过多消息后挂起

[英]Chat App Using React and Socket.io Hanging After Sending Too Many Messages

我的基本聊天应用程序在发送大约 7 条消息后变得非常慢,尽管它在只发送几条消息时确实有效。

我在返回的组件中放置了一个打印语句。 我注意到每次提交聊天消息时,打印语句的调用次数是以前的两倍。 我认为我的应用程序变得越来越慢,因为当我发送更多消息时,不得不以指数方式重新渲染 DOM。

有没有人对为什么会发生这种情况有任何想法?

这是我的 React 应用程序

import React from 'react';
import io from "socket.io-client";
let socket = io.connect("localhost:8080");

function App() {
  const [curMessage, setMessage] = React.useState({name: "", message: ""});
  const [messageList, setList] = React.useState([]);

  socket.on("receiveMsg", message => {
    setList([...messageList, message]);
  });

  function handleTyping(e) {
    let target = e.target;
    if (target.id === "name") {
      setMessage({...curMessage, name: target.value});
    } else {
      setMessage({...curMessage, message: target.value});
    }
  }

  function handleSubmit(e) {
    e.preventDefault();
    setList([...messageList, curMessage]);
    setMessage({name: "", message: ""});
    socket.emit("message", curMessage);
  }



  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input id="name" onChange={handleTyping} value={curMessage.name}></input>
        <input id="message" onChange={handleTyping} value={curMessage.message}></input>
        <button>Send Message</button>
      </form>
      <ul>
        {messageList.map(msg => {
          return <li> {msg.name} {msg.message} </li>
        })}
        {console.log("test")}
      </ul>
    </div>
  );
}

export default App;

这是我的服务器端代码(虽然我认为这段代码很好)

const express = require("express");
const app = express();
const http = require("http").createServer(app);
const io = require("socket.io")(http);

http.listen(8080, () => console.log("Connected to Server"));

io.on("connection", socket => {
  console.log("User has connected " + socket.id);
  socket.on("message", data => {
    socket.broadcast.emit("receiveMsg", data);
  });
});

尝试将socket.on(..)放在 useEffect 中。 也许在渲染中执行 setState 是速度变慢的原因。

useEffect(() => {
  socket.on("receiveMsg", (message) => {
    setList([...messageList, message]);
  });

  return () => {
    socket.off("receiveMsg");
  };
}, [messageList]);

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

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


您已将 socket.on 侦听器直接放置在您的组件中,而不是将其放置在任何钩子中。 这意味着每次您的组件重新渲染时都会创建一个新的 socket.on 侦听器。
  • 您的组件已安装 -> 您将拥有一个 socket.on 侦听器
  • 您收到第一条消息 -> 前一个监听器仍然存在,但由于组件重新渲染,将创建一个新的监听器
  • 您收到第 2 条消息 -> 前两个侦听器组合现在将导致总共 4 个侦听器

而这种模式还在继续..

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

 useEffect(() => { socket.on("receiveMsg", (message) => { setList([...messageList, message]); }); return () => { socket.off("receiveMsg"); }; }, [messageList]);

使用 [messageList] 作为 useEffect 的第二个参数的问题 ??

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

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

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

正确的代码

useEffect(() => { socket.on("receiveMsg", (message) => { setList([...messageList, message]); }); return () => { socket.off("receiveMsg"); }; }, []);

使用此代码,您将收到一条警告,提示您需要将messageList作为 useEffect 中的依赖项

useEffect(() => {
  socket.on("receiveMsg", (message) => {
    setList([...messageList, message]);
  });

  return () => {
    socket.off("receiveMsg");
  };
}, []);

你只需要像这样进行功能更新

setList((prevMsgs) => [...prevMsgs, message]);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM