【问题标题】:ReactJS fire an event into component when my global socket listener fires through socket当我的全局套接字侦听器通过套接字触发时,ReactJS 将事件触发到组件中
【发布时间】:2018-11-24 22:18:34
【问题描述】:

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

现在我想要的是,我想在我的消息事件监听器触发时触发一个事件到组件中,因为它被定义为一个全局函数。

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

提前致谢

【问题讨论】:

    标签: javascript reactjs websocket redux react-component


    【解决方案1】:

    我在这里为您制作了几个(自定义)事件调度示例:https://codesandbox.io/s/13287npq03。 (事件将记录到控制台 - 在控制台上展开它点击

    基础知识:

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

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

    请注意,您必须将该元素包含在您的组件渲染方法之一中。 例如。 render() { return <div id="idOfEventListener" /> }

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

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

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

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

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

    EventHelper.js

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

    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 方法和控制台日志 event & event.target(即 DOM 元素)。

    您可以在消息事件侦听器触发时调用 EventHelper.dispatchCustomEvent,或者如果您知道您的消息事件是什么样的 - 您可以在您需要的组件内侦听该消息事件。如果消息事件是全局的,我想它是在窗口或文档上创建事件 - 您必须像这样在 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

    具有 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 渲染 (&lt;p id="FirstChildEventListener"&gt;) 内的目标上侦听事件,并且该事件在另一个组件(父组件,但它可以很容易地从 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>
        );
      }
    }
    

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


    编辑


    我已将 GlobalFile.js 添加到带有 websocket 示例的代码沙箱中:

    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 元素 &lt;div id="elementInsideOfComponnet"&gt;Listening for global message&lt;/div&gt; 的 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。

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

    【讨论】:

    • 我没有任何 HTML 元素。我只有一个全局文件:let jsWebSocket = null;函数 initSocket(user_id) { jsWebSocket = new WebSocket("URL"); jsWebSocket.addEventListener('open', function (event) { jsWebSocket.addEventListener('message', function (event) { console.log('message listener failed'); }); }); } 导出 { initSocket, sendMessage, disconnectSocket, jsWebSocket };当消息事件从套接字触发时,我想在我的组件中触发一个事件。
    • 你的组件是什么样的?因为如果你有 Component,你的 Component 必须在 render 方法中有 DOM 元素?
    • 我知道您在该全局文件中没有 HTML 元素,但是您想要触发该事件的组件必须具有 DOM 元素(如果我们谈论的是 React 组件)。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-18
    • 2018-01-20
    • 2020-04-01
    • 2015-12-18
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多