React 和 Socket.io:能够获取初始数据 - 但是当有新帖子出现时视图不会更新

Posted

技术标签:

【中文标题】React 和 Socket.io:能够获取初始数据 - 但是当有新帖子出现时视图不会更新【英文标题】:React and Socket.io: Able to get initial data - but view doesn't update when a new post comes in 【发布时间】:2016-08-06 22:46:44 【问题描述】:

不确定问题是我的套接字设置方式 - 还是我错误地尝试使用 React 呈现数据。

我可以使用我的套接字成功地提取数据 - 但是当新数据发布到服务器时它不会实时更新状态。我的意图是让 React 中的状态自动呈现新数据,由于套接字连接,这些数据始终处于活动状态。

这是我的客户端应用程序,它从服务器获取消息并呈现它们:

var Chat = React.createClass(
  getInitialState: function() 
    return 
      messages: null
    
  ,
  componentWillMount: function()
    var self = this;
    socket.emit('getMessages');
    socket.on('serverMessages', function (data) 
      self.setState(messages: data)
    );
  ,
  render: function() 
    var messages = this.state.messages ? <MessageList messages=this.state.messages/> : null
    return (
      <div className="jumbotron">
         messages 
        <MessageForm submitMessage=this.submitMessage/>
      </div>
      );
  
);

以防万一这是我发出数据的服务器代码:

io.on('connection', function (socket) 

  socket.on('getMessages', function (data) 
    Message.find(function(err, messages)
      socket.emit('serverMessages', messages);
    )
  );

);

【问题讨论】:

【参考方案1】:

到目前为止,您“只是”在组件加载后从服务器获取数据。要获得更“实时”的东西,您需要使用您定期指定的相同 emit 语句来 ping 服务器(这违背了使用 websockets 的意义,实际上,您可以使用长轮询)或拥有服务器定期向所有客户端发送新数据。

你可以做到:

A) 客户端:“轮询”信息 [不理想]

注意:我最初把它放在我的答案中是因为我看到加载控制器时 OP 正在“轮询”。我没有点击这可能是因为控制器可能没有加载 websocket,所以在连接上发送数据可能在这里不起作用。我的错。

socket.emit('getMessages') 替换为会定期“轮询”websocket 以获取数据的东西:

setInterval(function () 
    socket.emit('getMessages')
, 10000); /* Request data from the socket every 10 seconds */

B) 服务器端:在可用时发送新数据。 [最佳方式]

通过客户端数组跟踪所有客户端,并在会话结束时将其删除。

var clients = [];

io.on('connection', function (socket) 
    clients.push(socket);

    socket.on('end', function () 
        // Could also splice the array below, but it still works.
        delete clients[clients.indexOf(socket)];
    );


    /* Previous logic for server goes here */
);

当您需要从数据库/数据存储推送新消息时运行此代码:

for (var i in clients) 
    clients[i].emit('serverMessages', /* messages object */);

【讨论】:

关于选项 A:在客户端上轮询听起来是不对的。连接到服务器套接字的客户端套接字不会创建实时数据流吗? 选项 B 是最好的方法 - 我以为我提到了这一点,但显然不是。我发布了你最初是在轮询的,但这样一来,当你连接到 websocket 时你的组件没有加载时,它是有意义的:P 在命名空间或房间上使用广播/发射可能比自己跟踪客户端(clients 数组)更安全(也更容易)。一旦开始运行多个节点实例,clients 数组将只包含连接到该特定主机的实例。 socket.io 默认情况下也是如此,但它确实有官方推荐的处理多个主机的方法socket.io/docs/using-multiple-nodes【参考方案2】:

这可能是由于 componentWillMount 生命周期方法吗?您可以尝试使用 componentDidMount 吗?

看起来 render 会看到状态更新,但只执行一次,尽管根据 facebook 进行了状态更改。

【讨论】:

【参考方案3】:

试试这个:

var Chat = React.createClass(
  getInitialState: function() 
    return 
      messages: null
    
  ,
  componentWillMount: function()
    var self = this;
    socket.emit('getMessages');
    socket.on('serverMessages', function (data) 
      self.setState(messages: data)
    );
  ,
  render: function() 
    var messages = this.state.messages ? <MessageList messages=this.state.messages/> : null
    return (
      <div className="jumbotron">
         messages 
        <MessageForm submitMessage=this.submitMessage/>
      </div>
      );
  
);

【讨论】:

【参考方案4】:

您的服务器代码仅在初始套接字connection 时触发。

服务器:

socket.on('getMessages', function (data) 
  Message.find(function(err, messages)
    socket.emit('serverMessages', messages);
  )
);

客户:

var Chat = React.createClass(
  getInitialState: function() 
    return 
      messages: null
    
  ,
  componentWillMount: function()
    var self = this;
    socket.emit('getMessages');
    socket.on('serverMessages', function (data) 
      self.setState(messages: data)
    );
  ,
  render: function() 
    var messages = this.state.messages ? <MessageList messages=this.state.messages/> : null
    return (
      <div className="jumbotron">
         messages 
      </div>
      );
  
);

根据命名约定,您的Message.find() 似乎也在提取一条消息。我建议澄清标签以匹配基数。

【讨论】:

代码是在浏览器中仓促编写的,没有经过测试,所以如果有错别字/逻辑错误,我深表歉意。原始示例中的关键缺陷是缺少 getMessages 的事件处理程序 感谢@kwcto - 我已经实施了您的反馈,但它的行为仍然相同。新消息仅在页面刷新时出现。 (我已经更新了问题以反映新的实施)

以上是关于React 和 Socket.io:能够获取初始数据 - 但是当有新帖子出现时视图不会更新的主要内容,如果未能解决你的问题,请参考以下文章

socket.io-client + react,在哪里连接服务器?

使用 HTTP keep-alive 和 websockets (socket.io) 时的 TCP 连接数

在 socket.io 中连接 2 个不同的应用程序(REACT NATIVE)

无法从带有 Socket.IO 的 cookie 中获取 Express 会话 ID

socket.io 连接不适用于 react.js

socket.io 广播不适用于 React