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