多个侦听器和 removeListener 删除所有内容 Socket.io

Posted

技术标签:

【中文标题】多个侦听器和 removeListener 删除所有内容 Socket.io【英文标题】:Multiple listeners & removeListener removes everything Socket.io 【发布时间】:2021-09-20 11:58:20 【问题描述】:

伙计们!我正在写一个 socket.io 聊天。当用户发送消息时,会发生 socket.on 事件。一切正常,但听众的数量呈指数级增长。我尝试使用 socket.off/socket.remove... 删除侦听器,将事件 socket.on 与连接分开 - 没有任何效果。拜托,请帮我弄清楚。我正在使用 react、node、socket 和 mongoDB

服务器部分:

const express = require("express");
const app = express();
const cors = require("cors");
const  UserModel  = require("./models");

app.use(cors());

app.use(express.json());
app.use(express.urlencoded( extended: true ));

app.options("http://localhost:3000", cors());
const mongoose = require("mongoose");
require("dotenv").config();

const http = require("http").createServer(app);
const io = require("socket.io")(http, 
  cors: 
    origin: ["http://localhost:3002"],
  ,
);

http.listen(3001, function () 
  console.log("Server is running");
);

io.on("connection", (socket) => 
  console.log("Socket connected", socket.id);

  socket.on("message:send", (data) => 
    console.log("Пришло в socket.onMessage", data);
    socket.emit("message:fromServer", data);
    // socket.removeListener("message:fromServer");
  );
);

const  userApi  = require("./api/userApi");
app.use("/", userApi);

app.use((err, _, res, __) => 
  return res.status(500).json(
    status: "fail",
    code: 500,
    message: err.message,
  );
);

const  PORT, DB_HOST  = process.env;

const dbConnection = mongoose.connect(DB_HOST, 
  useNewUrlParser: true,
  useFindAndModify: false,
  useCreateIndex: true,
  useUnifiedTopology: true,
);

dbConnection
  .then(() => 
    console.log("DB connect");
    app.listen(PORT || 3000, () => 
      console.log("server running");
    );
  )
  .catch((err) => 
    console.log(err);
  );

客户端部分: io.js

import  io  from "socket.io-client";

export const socket = io("http://localhost:3001/");

消息组件

import React from "react";
import  useState  from "react";
// import  useSelector  from "react-redux";
// import  getMessages  from "../../Redux/selectors";
import  socket  from "../helpers/io";
import Message from "../Message/Message";
import  nanoid  from "nanoid";

export default function MessageFlow() 
  const [message, setMessage] = useState([]);

  socket.on("message:fromServer", (data) => 
    console.log("На фронт пришло сообщение: ", data);
    setMessage([...message, data]);
    // setMessage((message) => [...message, data]);
    console.log("Массив сообщений компонента MessageFlow", message);
    console.log(socket.io.engine.transports);
    // socket.off();
    // getEventListeners(socket)['testComplete'][0].remove()
    // socket.removeListener("message:fromServer");
  );

  //   const dispatch = useDispatch();
  // const allMessages = useSelector(getMessages);
  return (
    <div id="mainDiv">
      message &&
        message.map((i) => 
          // return <Message />;
          return <Message content=i.userId id=nanoid() />;
        )
    </div>
  );

消息表单 - 发送过程的开始

import React,  useState  from "react";
import  useDispatch, useSelector  from "react-redux";
import  sendMessage  from "../../Redux/Chat/Chat-operations";
import  getUser  from "../../Redux/selectors";
import  getToken  from "../../Redux/Auth/Auth-selectors";
import  socket  from "../helpers/io";
import  useEffect  from "react";
import styles from "./MessageForm.module.css";

export default function MessageForm() 
  const [message, setMessage] = useState("");
  const dispatch = useDispatch();
  const userId = useSelector(getUser);
  const currentToken = useSelector(getToken);
  // const getAll = useSelector(allContacts);

  const updateMessage = (evt) => 
    setMessage(evt.target.value);
  ;

  const handleSubmit = (e) => 
    e.preventDefault();
    if (message) 
      socket.emit("message:send",  userId: message );
      dispatch(
        sendMessage(
          
            _id: userId,
            text: message,
          ,
          currentToken
        )
      );
     else 
      alert(`Молчать будем?`);
    
  ;
  return (
    <div className=styles.messageInputContainer>
      <form>
        <input
          type="text"
          value=message
          onChange=updateMessage
          required
          className=styles.messageInput
          placeholder="Type message to send"
        />
        <button
          type="submit"
          className=styles.messageAddBtn
          onClick=handleSubmit
        >
          Send
        </button>
      </form>
    </div>
  );

【问题讨论】:

【参考方案1】:

你在每次渲染时添加一个监听器,你应该使用 useEffect 钩子

export default function MessageFlow() 

  useEffect(()=> // triggered on component mount or when dependency array change
      const callback = (data) => 
        // what you want to do
      
      socket.on("message:fromServer", callback);
      return () =>  // on unmount, clean your listeners
        socket.removeListener('message:fromServer', callback);
      
  , []) // dependency array : list variables used in your listener
  // [...]

【讨论】:

以上是关于多个侦听器和 removeListener 删除所有内容 Socket.io的主要内容,如果未能解决你的问题,请参考以下文章

JavaFX检查是否正在侦听Node属性

如何避免ConcurrentModificationException听一次监听器的情况

递归删除多个 socket.io 监听器

DragSortListView-Android Studio 无法识别 dropListener 和 removeListener

当焦点在 contenteditable div 上时删除所有侦听器

删除匿名事件侦听器