提问者:小点点

带有React的socket.io在5个消息后表现奇怪


我试图用socket.io和react构建一个基本的聊天应用程序,但是遇到了一个奇怪的问题。 这款应用程序的工作方式就像预期的那样,可以处理前5条消息,但之后的第6条消息需要很长时间才能加载,而且之前的一些消息通常不会显示在聊天框中。 如果有人能帮忙我会很高兴的。 下面是我的后端代码:

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

io.on('connection', socket => {
  socket.on('message', ({ name, message }) => {
    io.emit('message', { name, message });
    console.log(message);
    console.log(name);
  });
});

http.listen(4000, function () {
  console.log('listening on port 4000');
});

下面是我在app.js中的代码:

import React, { useState, useEffect } from 'react';
import io from 'socket.io-client';

const App = props => {
  const socket = io.connect('http://localhost:4000');
  const [details, setDetails] = useState({ name: '', message: '' });
  const [chat, setChat] = useState([]);


  useEffect(() => {
    socket.on('message', ({ name, message }) => {
      setChat([...chat, { name, message }]); //same as {name:name,message:message}
    });
  });

  const onMessageSubmit = e => {
    e.preventDefault();
    const { name, message } = details;
    socket.emit('message', { name, message });
    setDetails({ name, message: '' });
  };

  return (
    <div>
      <form onSubmit={onMessageSubmit}>
        <input
          type='text'
          value={details.name}
          onChange={e => setDetails({ ...details, name: e.target.value })}
        />
        <input
          type='text'
          value={details.message}
          onChange={e => setDetails({ ...details, message: e.target.value })}
        />
        <button>Send</button>
      </form>
      <ul>
        {chat &&
          chat.map((chat, index) => (
            <li key={index}>
              {chat.name}:{chat.message}
            </li>
          ))}
      </ul>
    </div>
  );
};

export default App;


共1个答案

匿名用户

那是因为每次,您更新状态,useEffect回调运行,基本上您一次又一次地订阅message

在几次迭代之后,您就会有多个订阅试图更新相同的状态。 而且由于setstate的异步特性,您会看到奇怪的行为。

您只需要订阅一次,可以通过将空依赖项参数传递给UseEffect来实现这一点,这将使其工作方式与ComponentDidMount类似

 useEffect(() => {
    socket.on('message', ({ name, message }) => {
      setChat([...chat, { name, message }]);
    });
  }, []);

您可能希望在卸载组件时cleanup。 请看一下官方文件。