1

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

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

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

提前致谢

4

1 回答 1

0

我在这里为您制作了几个(自定义)事件调度示例: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 渲染 ( <p id="FirstChildEventListener">) 内的 target 上监听事件,并且该事件在另一个组件(父组件,但它可以很容易地从 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 元素的 ComponentListeningForGlobalEvent.js <div id="elementInsideOfComponnet">Listening for global message</div>,它将成为来自 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。

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

于 2018-06-15T09:33:05.080 回答