将 WebSockets 与 ReactJS 一起使用,不知道如何在客户端上呈现服务器消息



我正在尝试将 Socket.IO 与我的应用程序集成。我正在构建一个实时数据工具。现在,我只想看到我的服务器和客户端之间的持续通信。 我想发送一条简单的消息,每 5 秒将其记录在控制台上。

这是我的服务器.js:

const path = require('path');
const express = require('express');
const http = require("http");
const socketIo = require("socket.io");
const DIST_DIR = path.join(__dirname, 'public/');
const PORT = 3000;
const app = express();
app.use(express.static(DIST_DIR));
const server = http.createServer(app);
//wire up ExpressJS server to Socket.IO
const io = socketIo(server);
io.on("connection", (socket) => {
console.log("Connected to client"), setInterval(
() => socket.emit('testEvent', "Message from server sent"),
5000
);
socket.on("disconnect", () => console.log("Client disconnected"));
});
app.get('*', function(req, res) {
res.sendFile(path.join(DIST_DIR, "index.html"));
});
server.listen(PORT, () => console.log("server listening on port " + PORT));

在客户端上,我有(我正在使用DataMaps jQuery插件):

import propTypes from 'prop-types';
import React, { Component } from 'react';
import Datamaps from 'datamaps';
import socketIOClient from "socket.io-client";
export default class Datamap extends React.Component {
constructor(props) {
super(props);
this.state = {
response: false,
endpoint: "http://127.0.0.1:3000"
};
window.addEventListener('resize', this.resize);
}
resize() {
if (this.map) {
this.map.resize();
}
}
//creates a new connection to Socket.IO server
componentDidMount() {
const { endpoint } = this.state;
const socket = socketIOClient(endpoint);
socket.on("testEvent", data => this.setState({ response: data }));
this.drawMap();
}
componentWillReceiveProps() {
this.clear();
}
componentDidUpdate() {
this.drawMap();
}
componentWillUnmount() {
this.clear();
window.removeEventListener('resize', this.resize);
}
clear() {
const container = this.refs.container;
for (const child of Array.from(container.childNodes)) {
container.removeChild(child);
}
}
fadingBubbles(layer, data) {
//irrelevant, left out
}

drawMap() {
var map = new Datamaps({
...this.props,
element: this.refs.container,
projection: 'mercator',
responsive: true
});
if (this.props.arc) {
map.arc(this.props.arc, this.props.arcOptions);
}
if (this.props.bubbles) {
map.bubbles(this.props.bubbles, this.props.bubbleOptions);
}
if (this.props.graticule) {
map.graticule();
}
if (this.props.labels) {
map.labels();
}
this.map = map;
this.map.addPlugin('fadingBubbles', this.fadingBubbles.bind(this.map));
}
drawBubbles = () => {
const { response } = this.state;
var data = [
{
"latitude": "28.014067",
"longitude": "-81.728676"
}, {
"latitude": "40.750793",
"longitude": "-73.989525",
"magnitude": 3
}
];
this.map.fadingBubbles(data);
//console.log({ response });
}
render() {
const style = {
position: 'relative',
width: '100%',
height: '100%'
};
return (<div>
<button onClick={this.drawBubbles}>Draw Fading Bubbles</button>
<div ref="container" style={style}></div>
</div>);
}
}
Datamap.propTypes = {
arc: propTypes.array,
arcOptions: propTypes.object,
bubbleOptions: propTypes.object,
bubbles: propTypes.array,
graticule: propTypes.bool,
labels: propTypes.bool
};

所以,目前我有一个按钮。最终,函数 drawBubbles 将从服务器检索经度和经度信息,并将其输入地图以显示相应的气泡,但现在我只想要消息,我将能够弄清楚。按下按钮时,消息将打印在客户端的控制台上,这是正确的。但是我想摆脱该按钮并能够每 5 秒看到一次消息(因此没有 onclick 操作),正如我的服务器中所写的那样。我不完全确定组件挂载的工作原理,但是当我仅将函数调用this.drawBubbles;放在 render() 函数的返回之外时,我收到了以下警告(控制台上没有打印任何内容):

Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.
Please check the code for the Datamap component.

有人可以解释一下我如何让它工作吗?也许组件在我的应用程序上下文中的工作方式可能对我有用。

我怀疑它正在工作,但你不喜欢卸载时更新状态的警告(我也讨厌它,因为它暗示事情没有按预期管理)。我喜欢组件WillUnmount()的这个注释:

此方法中执行任何必要的清理,例如使计时器失效、取消网络请求或清理在 componentDidMount() 中创建的任何订阅。

也许可以考虑在 socket.io 客户端自己的实例中初始化它,该实例位于 Datamap 之外,以便可以将 socket.io 活动与 Datamap 组件的生存期分离。

下面是一个可以在数据映射实现中扩展的简单示例:

const socket = socketIOClient('http://127.0.0.1:3000');
let listener = null;
socket.on('testEvent', (data) => {
if (listener) {
listener.handleTestEvent({ response: data });
}
});
export class Datamap extends React.Component {
componentWillUnmount() {
listener = null;
}
componentDidMount() {
listener = {
handleTestEvent: (ev) => console.log(ev.response),
};
}
}

最新更新