简体   繁体   English

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

[英]Using WebSockets with ReactJS, do not know how to render server message on client

I'm trying to integrate Socket.IO with my application. 我正在尝试将Socket.IO与我的应用程序集成。 I'm building a real time data tool. 我正在构建一个实时数据工具。 For now, I just want to see constant communication between my server and the client. 现在,我只希望看到服务器与客户端之间的持续通信。 I want to send a simple message and log it on the console every 5 seconds. 我想发送一条简单的消息,并每5秒将其记录在控制台上一次。

Here is my server.js: 这是我的server.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));

On the client, I have (I'm using DataMaps jQuery plugin): 在客户端上,我有(我正在使用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
};

So, currently I have a button. 所以,目前我有一个按钮。 Eventually the function drawBubbles will retrieve lat and long information from the server and feed it into the map to display corresponding bubbles, but for now I just want the messages and I'll be able to figure that out. 最终,函数drawBubbles将从服务器中检索经纬度信息,并将其馈送到地图中以显示相应的气泡,但是现在我只想要消息,便可以弄清楚这一点。 When the button is pressed, the message is printed on the client's console, which is right. 当按下按钮时,消息将打印在客户端的控制台上,该控制台是正确的。 But I want to get rid of that button and be able to see the messages every 5 seconds (so without an onclick action), as written in my server. 但是我希望摆脱该按钮,并能够每隔5秒查看一次消息(因此无需onclick动作),就像写在服务器上一样。 I'm not entirely sure how component mounting works, but when I put merely the function call this.drawBubbles; 我不完全确定组件安装的工作方式,但是当我只放置函数调用this.drawBubbles; outside of the return inside the render() function, I got the following warning (and nothing printed on the console): 在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.

Could someone explain how I can get this to work? 有人可以解释我如何使它工作吗? Perhaps how components work in the context of my app could be of use to me. 也许组件在我的应用程序上下文中的工作方式可能对我有用。

I suspect it's working, but you don't like the warning that you're updating state when unmounted (I hate it too, because it hints that things are not managed as expected). 我怀疑它正在工作,但是您不喜欢警告 ,因为它在卸载时会更新状态(我也讨厌它,因为它暗示事物未按预期进行管理)。 I like this note for componentWillUnmount() : 我喜欢componentWillUnmount()的注释:

Perform any necessary cleanup in this method, such as invalidating timers, canceling network requests, or cleaning up any subscriptions that were created in componentDidMount(). 使用此方法执行任何必要的清除,例如使计时器无效,取消网络请求或清除在componentDidMount()中创建的所有订阅。

Perhaps consider initializing your socket.io client in its own instance, living outside of Datamap so that you may decouple socket.io activity from the lifetime of the Datamap component. 也许考虑在位于Datamap外部的实例中初始化socket.io客户端,以便可以将socket.io活动与Datamap组件的生命周期脱钩。

Here's a trivial example you can extend in your Datamap implementation: 这是一个简单的示例,您可以在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),
    };
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM