当我的全局套接字侦听器通过套接字

时间:2018-06-15 04:56:22

标签: javascript reactjs websocket redux react-component

我正在使用ReactJS,我已将连接套接字作为全局函数连接在不同的文件中。 有一个socket事件监听器,当任何新消息来自后端时会触发。

现在我想要的是,当我的消息事件监听器被定义为全局函数时,我想将事件激发到组件中。

任何人都可以有一个想法,我们该怎么做?

提前致谢

1 个答案:

答案 0 :(得分:0)

我在这里为您做了一些(自定义)事件调度示例:https://codesandbox.io/s/13287npq03。 (事件将记录到控制台 - 在控制台上单击enter image description here

进行扩展

基础:

  1. 如果你想在任何React组件中获取被触发的事件,你必须添加事件监听器,最好的做法是将它添加到componentDidMount中:

    componentDidMount = () => { let element = document.getElementById("idOfEventListener"); element.addEventListener("eventname", this.eventListener); };

  2. 请注意,您必须在其中一个Component render方法中包含该元素。 例如。 render() { return <div id="idOfEventListener" /> }

    1. 您必须拥有在事件发生时触发的方法。而不是element.addEventListener(“eventname”,this.eventListener);你也可以创建内联函数element.addEventListener("eventname", e => console.log('event occured', e));,否则你必须在你的Component中创建事件监听器方法:

      eventListener = e => { console.log("event occured in component", e, e.target); };

    2. 最佳做法是在组件卸载时清理(删除事件侦听器):

      componentWillUnmount = () => { let element = document.getElementById("idOfEventListener"); element.removeEventListener( "eventname", EventHelper.dispatchCustomEvent, false ); };

    3. https://codesandbox.io/s/13287npq03的解释:

        

      EventHelper.js

      我在分离文件中创建了通用dispatchCustomEvent方法,因此您可以从任何组件中使用它(和调度事件)。它接受目标(DOM元素,例如document.getElementById('idOfEventListener')),事件名称(它必须与您正在侦听的名称相同,在上面的addEventListener我指定我只是在监听“eventname”)和详细信息 - &gt ;您想要提供的自定义数据,对象/字符串/数字,无论您需要什么。

      export default {
        dispatchCustomEvent: (target, name, details) => {
          if (target) {
            let event = new Event(name, {
              details: details,
              bubbles: true,
              cancelable: true
            });
      
            target.dispatchEvent(event);
          }
        }
      };
      

      对于上面的事件监听器,我必须调用EventHelper.dispatchCustomEvent(document.getElementById("idOfEventListener"), "eventname", {test: "whatever data you need"}),我的监听器将触发this.eventListener方法和控制台日志事件&amp; event.target(这将是DOM元素)。

        

      您可以在消息事件侦听器触发时调用EventHelper.dispatchCustomEvent,或者如果您知道消息事件的样子 - 您可以在您需要的Component内部侦听该消息事件。如果message事件是全局的,我想它是在窗口或文档上创建事件 - 你必须在Component上创建事件监听器,如下所示:

        componentDidMount = () => {
          let element = window || document;
      
          element.addEventListener("messageEventName", this.eventListener);
        };
      
        eventListener = e => {
          console.log("event inside second child component:", e, e.target);
        };
      
        componentWillUnMount = () => {
          let element = window || document;
          element.removeEventListener(
            "messageEventName",
            EventHelper.dispatchCustomEvent,
            false
          );
        };
      

      其他组件:

        

      index.js

      Main / Parent Component,包含2个子组件FirstChildComponent和SecondChildComponent。我在渲染中创建了2个按钮 - 第一个按钮将触发FirstChildComponent正在侦听的事件,第二个按钮将触发由父(index.js)和SecondChildComponent侦听的事件“eventname”,它将触发两个父母和第二个孩子的事件听众。请注意,我没有将该事件绑定到窗口或文档,而是创建了<div id="idOfEventListener">,它是整个应用程序的包装器,SecondChildComponent和父级都可以将它用作事件侦听器目标并获取针对它的事件

      import React, { Component } from "react";
      import FirstChildComponent from "./FirstChildComponent";
      import SecondChildComponent from "./SecondChildComponent";
      import ReactDOM from "react-dom";
      import EventHelper from "./EventHelper";
      
      class App extends Component {
        componentDidMount = () => {
          let element = document.getElementById("idOfEventListener");
      
          element.addEventListener("eventname", this.eventListener);
        };
      
        eventListener = e => {
          console.log("event in parent component", e, e.target);
        };
      
        componentWillUnMount = () => {
          let element = document.getElementById("idOfEventListener");
          element.removeEventListener(
            "eventname",
            EventHelper.dispatchCustomEvent,
            false
          );
        };
      
        fireEvent = () => {
          let additionalData = { loremIpsum: "dolor sit amet" };
          let target = document.getElementById("FirstChildEventListener");
          EventHelper.dispatchCustomEvent(
            target,
            "firstChildEventName",
            additionalData
          );
        };
      
        fireMultipleListenedEvent = () => {
          console.log("fire multiple");
          let additionalData = { test: "blabla" };
          let target = document.getElementById("idOfEventListener");
          EventHelper.dispatchCustomEvent(target, "eventname", additionalData);
        };
      
        render() {
          return (
            <div id="idOfEventListener" className="App">
              <h1>Parent Component</h1>
              <div id="GettingEventInParentComponent">
                Box in parent component listening for event
              </div>
              <button onClick={this.fireEvent}>
                Test Button that will fire event which FirstComponent will receive
              </button>
      
              <FirstChildComponent />
              <SecondChildComponent />
      
              <hr />
      
              <button onClick={this.fireMultipleListenedEvent}>
                Test Button that will fire event which is listened inside of Second
                Child Component and parent component both
              </button>
            </div>
          );
        }
      }
      
      const rootElement = document.getElementById("root");
      ReactDOM.render(<App />, rootElement);
      
        

      FirstChildComponent

      在FirstChildComponent渲染(<p id="FirstChildEventListener">)内部的目标上侦听事件,并且该事件在另一个组件内部触发(父级,但它可以很容易地从SecondChildComponent触发,并且侦听器仍然会获得它) :

      import React, { Component } from "react";
      import EventHelper from "./EventHelper";
      
      export default class FirstChildComponent extends Component {
        componentDidMount = () => {
          var element = document.getElementById("FirstChildEventListener");
      
          element.addEventListener("firstChildEventName", this.eventListener);
        };
      
        eventListener = e => {
          console.log("event inside first child component:", e, e.target);
        };
      
        componentWillUnMount = () => {
          var element = document.getElementById("FirstChildEventListener");
          element.removeEventListener(
            "firstChildEventName",
            EventHelper.dispatchCustomEvent,
            false
          );
        };
      
        render() {
          return (
            <div className="App">
              <h1>First Child Component</h1>
              <p id="FirstChildEventListener">
                This element is inside of FirstChildComponent, and it only listens
                when event will be dispatched
              </p>
            </div>
          );
        }
      }
      
        

      SecondChildComponent.js

      在其渲染之外的(父)DOM元素上侦听事件。

      import React, { Component } from "react";
      import EventHelper from "./EventHelper";
      
      export default class FirstChildComponent extends Component {
        componentDidMount = () => {
          let element = document.getElementById("idOfEventListener");
      
          element.addEventListener("eventname", this.eventListener);
        };
      
        eventListener = e => {
          console.log("event inside second child component:", e, e.target);
        };
      
        componentWillUnMount = () => {
          let element = document.getElementById("idOfEventListener");
          element.removeEventListener(
            "eventname",
            EventHelper.dispatchCustomEvent,
            false
          );
        };
      
        render() {
          return (
            <div className="App">
              <h1>Second Child Component</h1>
              <span>Listening event on upper level</span>
            </div>
          );
        }
      }
      

      我正在从父组件触发事件(在按钮上单击),但您可以在事件侦听器内部触发事件,然后在您需要的组件内为该确切事件创建事件侦听器。

        

      修改

      我已经使用websocket的例子将GlobalFile.js添加到codesandbox中:

      import EventHelper from "./EventHelper";
      
      // or just copy dispatchCustomEvent function
      /*function dispatchCustomEvent (target, name, details) {
        if (target) {
          let event = new Event(name, {
            details: details,
            bubbles: true,
            cancelable: true
          });
      
          target.dispatchEvent(event);
        }
      }*/
      
      let jsWebSocket = null;
      
      function initSocket(user_id) {
        jsWebSocket = new WebSocket("wss://demos.kaazing.com/echo");
        jsWebSocket.addEventListener("open", function(event) {
          jsWebSocket.addEventListener("message", function(event) {
            console.log("message listener fired");
            let elementInsideOfComponent = document.getElementById(
              "elementInsideOfComponnet"
            );
            let someData = { id: "message1" };
            // if element target exists dispatch event to component
            console.log(elementInsideOfComponent);
            if (elementInsideOfComponent)
              EventHelper.dispatchCustomEvent(
                elementInsideOfComponent,
                "websocketmessage",
                someData
              );
          });
        });
      }
      
      function sendMessage() {
        jsWebSocket.send("Here's some text that the server is urgently awaiting!");
      }
      
      export default { initSocket, sendMessage, jsWebSocket };
      

      添加了具有DOM元素<div id="elementInsideOfComponnet">Listening for global message</div>的ComponentListeningForGlobalEvent.js,它将成为来自websocket消息事件的调度事件的目标:

      import React, { Component } from "react";
      import EventHelper from "./EventHelper";
      
      export default class ComponentListeningForGlobalEvent extends Component {
        componentDidMount = () => {
          let element = document.getElementById("elementInsideOfComponnet");
      
          element.addEventListener("websocketmessage", this.eventListener);
        };
      
        eventListener = e => {
          console.log("websocketmessage event inside component:", e, e.target);
        };
      
        componentWillUnMount = () => {
          let element = document.getElementById("elementInsideOfComponnet");
          element.removeEventListener(
            "websocketmessage",
            EventHelper.dispatchCustomEvent,
            false
          );
        };
      
        render() {
          return (
            <div className="App">
              <h1>Component that will receive event from websocket</h1>
      
              <div id="elementInsideOfComponnet">Listening for global message</div>
            </div>
          );
        }
      }
      

      还补充说:

        constructor(props) {
          super(props);
      
          GlobalFile.initSocket("id");
        }
      

      到index.js(父组件)来初始化websocket连接。以及index.js的渲染:

      <ComponentListeningForGlobalEvent />
      <button onClick={GlobalFile.sendMessage}>Send websocket message</button>
      

      将从websocket消息接收事件的插入组件,以及触发webscket发送消息的按钮,以便您可以测试(并查看)websocket消息事件一直传播到ComponentListeningForGlobalEvent。

      我真的希望这会有所帮助! :)