我正在使用 ReactJS,并且我已经连接了不同文件中的套接字作为全局函数。有一个套接字的消息事件侦听器,并在任何新消息来自后端时触发。
现在我想要的是,当我的消息事件侦听器被定义为全局函数时,我想在组件中触发一个事件。
任何人都可以有一个想法,我们怎么做?
提前致谢
我正在使用 ReactJS,并且我已经连接了不同文件中的套接字作为全局函数。有一个套接字的消息事件侦听器,并在任何新消息来自后端时触发。
现在我想要的是,当我的消息事件侦听器被定义为全局函数时,我想在组件中触发一个事件。
任何人都可以有一个想法,我们怎么做?
提前致谢
我在这里为您制作了几个(自定义)事件调度示例:https ://codesandbox.io/s/13287npq03 。(事件将记录到控制台 - 在控制台单击展开它)
基本:
如果你想在任何 React 组件中触发事件,你必须添加事件监听器,最好的做法是在 componentDidMount 中添加它:
componentDidMount = () => {
let element = document.getElementById("idOfEventListener");
element.addEventListener("eventname", this.eventListener);
};
请注意,您必须将该元素包含在您的组件渲染方法之一中。例如render() { return <div id="idOfEventListener" /> }
您必须有在事件发生时触发的方法。而不是 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);
};
最佳做法是在组件卸载时清理(删除事件侦听器):
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。
我真的希望这会有所帮助!:)