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)