首页 > 解决方案 > 使用带有 ReactJS 和 ExpressJS 的 Socket.io 时浏览器挂起

问题描述

问题:

我正在开发一个聊天应用程序。当我发送超过 9-10 个请求时,浏览器会变慢,最终会挂起。刷新页面后,一切恢复正常。我搜索了 socket.io 文档,但没有找到关于这个问题的任何解决方案。

代码:

这是我的后端 Express.JS 代码:

index.js

const express = require("express");
const { addUser, getUser, deleteUser, getAllUsers } = require("./users_api");
const app = express();
const server = require("http").createServer(app);
const io = require("socket.io")(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"],
  },
});

const port = 5000 || process.env.PORT;

io.on("connection", (socket) => {
  socket.on("join", ({ name, room }, callback) => {
    const { err, user } = addUser({ id: socket.id, name, room });
    if (err) return callback(err);
    if (user) {
      socket.emit("message", {
        user: "admin",
        text: `${user.name} has entered the room ${user.room}.`,
      });
      socket.broadcast.to(user.room).emit("message", {
        user: "admin",
        text: `${user.name} has joined the room.`,
      });
      socket.join(user.room);
      io.to(user.room).emit("users", {
        room: user.room,
        users: getAllUsers(user.room),
      });

      callback();
    }
  });

  socket.on("client_message", (msg) => {
    const user = getUser(socket.id);
    if (user) io.to(user.room).emit("message", { user: user.name, text: msg });
  });

  socket.on("disconnect", () => {
    console.log(6);
    const user = deleteUser(socket.id);
    if (user) {
      io.to(user.room).emit("message", {
        user: "admin",
        text: `${user.name} has left the room.`,
      });
      io.to(user.room).emit("users", {
        room: user.room,
        users: getAllUsers(user.room),
      });
    }
  });
});

server.listen(port, () => console.log(`Server started at port ${port}.`));

users_api.js:

const current_users = [];

const addUser = ({ id, name, room }) => {
  name = name.trim().toLowerCase().split(" ").join("_");
  room = room.trim().toLowerCase();

  const exist_user = current_users.find(
    (user) => name === user.name && room === user.room
  );

  if (exist_user)
    return {
      err: "User with this name already exists.",
    };

  current_users.push({ id, name, room });
  return { user: { id, name, room } };
};

const deleteUser = (id) => {
  const index = current_users.findIndex((user) => user.id === id);
  if (index !== -1) return current_users.splice(index, 1)[0];
};

const getUser = (id) => current_users.find((user) => user.id === id);

const getAllUsers = (room) =>
  current_users.filter((user) => user.room === room);

module.exports = { addUser, deleteUser, getUser, getAllUsers };

前端代码:

import io from "socket.io-client";
import React, { useEffect, useRef, useState } from "react";
import queryString from "query-string";
import "./ChatPage.css";

const END_POINT = "http://localhost:5000";

const ChatPage = (props) => {
  const [message, setMessage] = useState("");
  const [messages, setMessages] = useState([]);
  const [users, setUsers] = useState([]);
  const socket = useRef(null);

  const handleSubmit = () => {
    socket.current.emit("client_message", message);
    setMessage("");
  };

  useEffect(() => {
    const { name, room } = queryString.parse(props.location.search);
    socket.current = io(END_POINT);
    socket.current.emit("join", { name, room }, (error) => {
      if (error) alert(error);
    });

    return () => {
      socket.current.disconnect();
      socket.current.off();
    };
  }, [props.location.search, END_POINT]);

  useEffect(() => {
    socket.current.on("message", (msg) => {
      setMessages([...messages, msg]);
    });
    socket.current.on("users", ({ users }) => {
      setUsers(users);
    });
  }, [messages.length]);

  return (
    <div className="chat-room-container">
      <div className="chat-room-left">
        <ul>
          {messages.map((message, i) => (
            <li key={i}>
              {message.name}
              {message.text}
            </li>
          ))}
        </ul>
        <input
          type="text"
          value={message}
          onChange={(e) => setMessage(e.target.value)}
        />
        <button type="button" onClick={handleSubmit}>
          Submit
        </button>
      </div>
      <div className="chat-room-right">
        <ul>
          {users.map((user, i) => (
            <li key={i}>{user.name}</li>
          ))}
        </ul>
      </div>
    </div>
  );
};

export default ChatPage;

我不明白怎么回事,请帮忙。

标签: node.jsreactjsexpresssocket.io

解决方案


您在每个 useEffect 上创建新的套接字连接,因此在十条消息之后,您有十个连接。

socket = io(END_POINT);

我将创建的套接字连接存储在 useRef - 所以如果再次创建它,它会被新的覆盖 - 它不会重复。

const socketConection = useRef(null)

useEffect(() => {
  socketConnection.current = io(END_POINT)
}, [deps])

当然,在以下所有用途中,您必须使用socketConection.current


推荐阅读