I would like to integrate web components into my react app. They define a set of custom events that the enclosing react app must listen to.
According to the 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.
I've struggled to make this work. I can dispatch custom events from react components and listen to them on dom elements. But I can't catch these events on other react components.
How do I correctly listen to custom events (and ideally, also be able to dispatch them) from a react app?
Minimal example:
I've set up a minimal example (edit live on sandbox.io). It consists of two divs, the outer one listens to my custom event, the inner one hosts the virtual dom. In the virtual dom there are two components. The outer one listens to the custom event, the inner one dispatches it. When run, the outer div registers the custom event. Inside of the react app, it is not caught.
If you want to play around with the code, I've set it up as a repo:
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
, contains a div which will listen to custom dom elements, and inside of it is the root of the react app.
<div id='listener'>
<div id="react_root"></div>
</div>
The react app consists of two functional components: Listener and Dispatcher. index.tsx
renders the react app and sets up a listener on the dom div
:
document.getElementById("listener")?.addEventListener("custom", ev => {
console.log("dom received custom event");
});
ReactDOM.render(<Listener />, document.getElementById("react_root"));
And here are the two components, they dispatch and listen to the custom dom event.
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>
);
}
Finally, the custom event is declared like this:
export var customEvent = new Event('custom', { bubbles: true });
Related questions:
This question sounds very similar: Listening for web component events in React
But it's not really about the system of custom events in react. Instead it asks on how to expose an event attribute on a polymer component.
This question is also about custom events, but not in the context of react: How to listen for custom events defined web component
This question seems to be just a syntax error: addEventListener in a React app isn't working