反应:派发和收听自定义事件
react: dispatch and listen to custom events
我想将 Web 组件集成到我的 React 应用程序中。它们定义了一组自定义事件,封闭的 React 应用程序必须监听这些事件。
根据 react docs:
Events emitted by a Web Component may not properly propagate through a
React render tree. You will need to manually attach event handlers to
handle these events within your React components.
我一直在努力完成这项工作。我可以从 React 组件分派自定义事件并在 dom 元素上收听它们。但是我无法在其他反应组件上捕获这些事件。
如何从 React 应用程序正确地监听自定义事件(理想情况下,也能够调度它们)?
最小示例:
我设置了一个最小示例 (edit live on sandbox.io)。它由两个 div 组成,外层监听我的自定义事件,内层承载虚拟 dom。在虚拟 dom 中有两个组件。外层监听自定义事件,内层调度它。当运行时,外层div注册自定义事件。在 React 应用程序内部,它没有被捕获。
如果您想使用代码,我已将其设置为存储库:
git clone https://github.com/lhk/react_custom_events
cd react_custom_events
npm i
npm run start
# browser opens, look at the console output
index.html
,包含一个 div,它将监听自定义 dom 元素,其中是 React 应用程序的根。
<div id='listener'>
<div id="react_root"></div>
</div>
react 应用程序由两个功能组件组成:Listener 和 Dispatcher。 index.tsx
呈现 React 应用程序并在 dom div
:
上设置监听器
document.getElementById("listener")?.addEventListener("custom", ev => {
console.log("dom received custom event");
});
ReactDOM.render(<Listener />, document.getElementById("react_root"));
这是两个组件,它们分派和侦听自定义 dom 事件。
Listener.tsx
:
import React, { useEffect, useRef } from "react";
import Dispatcher from "./Dispatcher";
export default function Listener() {
const divRef = useRef(null);
useEffect(() => {
(divRef.current as any).addEventListener("custom", (ev:any) => {
console.log("react received custom event");
});
});
return (
<div ref={divRef}>
<Dispatcher />
</div>
);
}
Dispatcher.tsx
:
import React, { useEffect, useRef } from "react";
import { customEvent } from "./events";
export default function Dispatcher() {
const pRef = useRef(null);
useEffect(() => {
(pRef.current as any).dispatchEvent(customEvent);
});
return (
<div>
<p ref={pRef}>Some Text</p>
</div>
);
}
最后,自定义事件声明如下:
export var customEvent = new Event('custom', { bubbles: true });
相关问题:
这个问题听起来很相似:Listening for web component events in React
但这并不是关于反应中的自定义事件系统。相反,它询问如何在聚合物组件上公开事件属性。
这个问题也是关于自定义事件的,但不是在react的上下文中:
这道题好像只是语法错误:
在我看来,这在 React 中是不可能的。
React 提供了一个合成事件系统。这是出于兼容性原因而实现的,合成事件在浏览器中公开相同的 API。在内部,React 将原生 DOM 事件包装成合成事件。
但是,这些合成事件也引入了一系列限制:
- 合成事件并未涵盖所有原生事件。最值得注意的是 onInput 和 onChange 发生了变化。
- 自定义事件没有合成版本
- 本机(自定义)事件将在虚拟 dom 中冒泡,而不会触发任何事件侦听器。离开虚拟 dom 后,他们将继续在 dom 的剩余部分冒泡。这就是我的示例代码中发生的情况。
- 无法自行调度合成事件
可以在虚拟 dom 中监听自定义事件,但只能在调度它们的同一元素上监听 。以下代码将捕获该事件:
export default function Dispatcher() {
const pRef = useRef(null);
useEffect(() => {
(pRef.current as any).addEventListener('custom', ()=>{
console.log('react caught custom event directly on component');
});
(pRef.current as any).dispatchEvent(customEvent);
});
return (
<div>
<p ref={pRef}>Some Text</p>
</div>
);
}
我认为这会使自定义事件变得毫无用处。如果您必须获得对触发自定义事件的特定 dom 节点的引用,您不妨给它一个回调。
如果您有兴趣阅读此内容,可以找到各种 github 问题。不幸的是,Facebook React 团队似乎对它们进行了相当大的调整。他们只是关闭而没有进一步评论:(
我想将 Web 组件集成到我的 React 应用程序中。它们定义了一组自定义事件,封闭的 React 应用程序必须监听这些事件。
根据 react docs:
Events emitted by a Web Component may not properly propagate through a React render tree. You will need to manually attach event handlers to handle these events within your React components.
我一直在努力完成这项工作。我可以从 React 组件分派自定义事件并在 dom 元素上收听它们。但是我无法在其他反应组件上捕获这些事件。
如何从 React 应用程序正确地监听自定义事件(理想情况下,也能够调度它们)?
最小示例:
我设置了一个最小示例 (edit live on sandbox.io)。它由两个 div 组成,外层监听我的自定义事件,内层承载虚拟 dom。在虚拟 dom 中有两个组件。外层监听自定义事件,内层调度它。当运行时,外层div注册自定义事件。在 React 应用程序内部,它没有被捕获。
如果您想使用代码,我已将其设置为存储库:
git clone https://github.com/lhk/react_custom_events
cd react_custom_events
npm i
npm run start
# browser opens, look at the console output
index.html
,包含一个 div,它将监听自定义 dom 元素,其中是 React 应用程序的根。
<div id='listener'>
<div id="react_root"></div>
</div>
react 应用程序由两个功能组件组成:Listener 和 Dispatcher。 index.tsx
呈现 React 应用程序并在 dom div
:
document.getElementById("listener")?.addEventListener("custom", ev => {
console.log("dom received custom event");
});
ReactDOM.render(<Listener />, document.getElementById("react_root"));
这是两个组件,它们分派和侦听自定义 dom 事件。
Listener.tsx
:
import React, { useEffect, useRef } from "react";
import Dispatcher from "./Dispatcher";
export default function Listener() {
const divRef = useRef(null);
useEffect(() => {
(divRef.current as any).addEventListener("custom", (ev:any) => {
console.log("react received custom event");
});
});
return (
<div ref={divRef}>
<Dispatcher />
</div>
);
}
Dispatcher.tsx
:
import React, { useEffect, useRef } from "react";
import { customEvent } from "./events";
export default function Dispatcher() {
const pRef = useRef(null);
useEffect(() => {
(pRef.current as any).dispatchEvent(customEvent);
});
return (
<div>
<p ref={pRef}>Some Text</p>
</div>
);
}
最后,自定义事件声明如下:
export var customEvent = new Event('custom', { bubbles: true });
相关问题:
这个问题听起来很相似:Listening for web component events in React
但这并不是关于反应中的自定义事件系统。相反,它询问如何在聚合物组件上公开事件属性。
这个问题也是关于自定义事件的,但不是在react的上下文中:
这道题好像只是语法错误:
在我看来,这在 React 中是不可能的。
React 提供了一个合成事件系统。这是出于兼容性原因而实现的,合成事件在浏览器中公开相同的 API。在内部,React 将原生 DOM 事件包装成合成事件。
但是,这些合成事件也引入了一系列限制:
- 合成事件并未涵盖所有原生事件。最值得注意的是 onInput 和 onChange 发生了变化。
- 自定义事件没有合成版本
- 本机(自定义)事件将在虚拟 dom 中冒泡,而不会触发任何事件侦听器。离开虚拟 dom 后,他们将继续在 dom 的剩余部分冒泡。这就是我的示例代码中发生的情况。
- 无法自行调度合成事件
可以在虚拟 dom 中监听自定义事件,但只能在调度它们的同一元素上监听 。以下代码将捕获该事件:
export default function Dispatcher() {
const pRef = useRef(null);
useEffect(() => {
(pRef.current as any).addEventListener('custom', ()=>{
console.log('react caught custom event directly on component');
});
(pRef.current as any).dispatchEvent(customEvent);
});
return (
<div>
<p ref={pRef}>Some Text</p>
</div>
);
}
我认为这会使自定义事件变得毫无用处。如果您必须获得对触发自定义事件的特定 dom 节点的引用,您不妨给它一个回调。
如果您有兴趣阅读此内容,可以找到各种 github 问题。不幸的是,Facebook React 团队似乎对它们进行了相当大的调整。他们只是关闭而没有进一步评论:(