Socket.io - React:如何在 React 中检索保存的 socket.io 数据(MongoDB)?

Posted

技术标签:

【中文标题】Socket.io - React:如何在 React 中检索保存的 socket.io 数据(MongoDB)?【英文标题】:Socket.io - React : How to retrieve saved socket.io data (MongoDB) in React? 【发布时间】:2019-07-20 16:14:06 【问题描述】:

在加入之前,我遵循了一些关于如何显示在聊天室中发送的消息的教程,但我不知道如何在 React 中显示它们,并且我在服务器端有几个问题。

客户端,在构造函数中:

this.state = 
 msg: "",
 messages: []
;

客户端,我有一个表单,点击按钮将通过此功能将消息发送到服务器:

sendMessage(e) 
 e.preventDefault();
 let msg = this.state.msg;
 this.socket.emit("sendMessage", msg);
 this.setState( msg: "" );

服务器端,我有一个用于消息的猫鼬模式,名为 Message,数据库中的集合是消息。

const Message = new mongoose.Schema(
 sender: 
  type: "string"
 ,
 message: 
  type: "string"
 
);

var messages = [];

io.on("connection", (socket, user) => 
var user = socket.request.session.user;

Message.find().exec((err, messages) => 
 if (err) throw err;
 console.log(messages);
 io.emit("showingPastMessages", messages);
);

console.log(messages) 在 PowerShell 中显示保存在 Mongo 中的 javascript 对象数组中的所有消息(条目)? [id_:4qxxx,发件人:'user123',消息:'hello!',id_:5exxx,发件人:'user456',消息:'hi!'] 我想知道是否可以仅访问 sender 和 message 属性以将其发送给客户端?像 messages.sender + messages.message 这样的东西,因为当我 console.log(messages.message) 它显示未定义

这里是服务器接收发送的消息然后将其保存在 Mongo 中的地方。

socket.on("sendMessage", function(msg) 
var newMsg = new Message( message: msg, sender: user );
 newMsg.save(function(err) 
   if (err) 
     console.log(err);
    else 
     messages.push(newMsg);
     console.log(newMsg);
     console.log(messages);
   
 );
);

console.log(newMsg) 显示最新发送的消息,但是console.log(messages) 不显示以前的消息,而只显示最新的消息,为什么?

那么在 React 中,我应该在构造函数中,在 ComponentDidMount() 中有类似的东西吗?如果应该是prevState

this.socket.on("showingPastMessages", function(messages)
 this.setState( ...this.state.messages, messages)
);

你能给我一些建议吗?

这是我检索数据的客户端代码:

class Chat extends Component 
 constructor(props) 
 super(props);

 this.state = 
  msg: "",
  messages: []
 ;

 var socket = io('http://localhost:3000');
 this.socket.on("history", function(messages) 
  console.log(messages);
 );

【问题讨论】:

您可以将套接字添加到连接socket.join('room'); 的房间,然后发送到您保存消息io.to('room').emit('message', msg); 的房间。如果这有帮助,我会输入更详尽的答案。 是的,但新加入的用户看不到聊天室中发送的先前消息?我在***上搜索了将消息存储在数据库中的信息,即使您不在房间里也可以显示以前的消息。不知道我解释的好不好 我发布了一个更彻底的答案。让我知道你的想法。 【参考方案1】:

这是一个好的开始。我建议做的是让这更受事件驱动。为此,您需要在连接时将套接字添加到房间。有多少房间以及如何划分房间取决于您的应用,但我将演示基本概念。

首先,当一个套接字连接到您的服务器时,将该套接字添加到房间并立即发出您的聊天记录。

io.on('connection', async (socket) => 
  socket.user = socket.request.session.user;

  socket.join('chat');

  try 
    const messages = await Message.find();

    socket.emit('history', messages);
   catch (err) 
    // Handle this error properly.
    console.error(err);
  
);

然后,稍后,当您收到一条消息时,您会想要保存该消息并将其发送到您聊天室中的所有套接字。

socket.on("sendMessage", (msg, callback) => 
  const message = new Message( message: msg, sender: socket.user );

  message.save(function(err) 
    if (err) 
      return callback(err);
    

    io.to('chat').emit('message', message);
  );
);

最后,在客户端,您需要监听历史事件。当您收到它时,您会想要清除您当前拥有的聊天记录并将其替换为服务器告诉您的内容。也许这看起来像

socket.on('history', (messages) => 
  this.setState( messages );
);

您还需要收听此message 事件,但对于此事件,您只会将消息附加到您的历史记录中。这可能看起来像

socket.on('message', (message) => 
  this.setState( messages: [ ...messages, message ] );
);

提醒一句,如果当你告诉服务器一条新消息时,不要将它添加到你的messages 状态数组中,直到你收到message 事件。如果这样做,您会注意到双重消息。例如,这可能看起来像

onSendMessage(evnt) 
  evnt.preventDefault();

   socket.emit("sendMessage", msg);
   this.setState( msg: "" );

注意:在收到 OP 的一些反馈后,我想添加一个部分,说明将事件处理程序附加到套接字的位置(即所有 socket.ons)。我的建议是将此代码添加到在io.on('connection') 回调中文件底部定义Message 架构的文件中。例如,

const Message = new mongoose.Schema(/*...*/);

io.on('connection', (socket) => 
  // Everything else I wrote above...

  socket.on('sendMessage', (msg, callback) => 
    // ...
  );
);

在客户端,可能会在挂载聊天组件时注册事件处理程序。例如,

class ChatComponent extends React.Component 
  componentDidMount() 
    this.socket = io('https://your-server-or-localhost/');

    this.socket.on('history', (messages) => 
      // See above...
    );
  

【讨论】:

感谢您的回答,我对您的代码有几个问题,什么是 const messages = Message.find() ?它应该是一个对象数组,你可以像这样将它发送给客户端吗?在构造函数中,您会将 socket.on 放在哪里? 抱歉,我打错了几个字。 const messages = Message.find() 应该是 (const messages = await Message.find();`,它将返回一个包含您迄今为止保存的所有消息的数组。是的,您应该能够像这样将它发送给客户端。 socket.on 的放置位置取决于您的应用;但是,根据您的示例,您可以将其放在您定义消息模式的同一文件中的 io.on('connection', (socket) => ); 中。 我明白了!但我的问题是如何在页面加载后立即显示消息?我在页面中有一个聊天室,我希望在加载页面时之前的消息在那里。我会在哪里写客户端 socket.on("history", ...) ? 这有点取决于您的设置,但可能在您建立套接字连接或组件安装时的同一位置。由于该事件在连接后立即触发,因此必须在套接字连接完成时已经在监听。

以上是关于Socket.io - React:如何在 React 中检索保存的 socket.io 数据(MongoDB)?的主要内容,如果未能解决你的问题,请参考以下文章