Reputation: 53
I followed React's documentation on how to use React inside of a Web Component (https://reactjs.org/docs/web-components.html) but found that the synthetic event system just does not work for the React tree inside of that React component.
Here is a JS Fiddle where you can try:
class CounterWithSyntheticEvents extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
};
}
handleClick() {
this.setState(prevState => ({ counter: prevState.counter + 1 }));
}
render() {
return (
<div>
Count {this.state.counter} <button onClick={this.handleClick.bind(this)}>+</button>
</div>
);
}
}
class CounterWithDOMEvents extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
this.state = {
counter: 0,
};
}
componentDidMount() {
const listenerFn = this.handleClick.bind(this);
this.buttonRef.current.addEventListener("click", listenerFn);
this.removeListener = () => this.buttonRef.current.removeEventListener('click', listenerFn);
}
componentWillUnmount() {
this.removeListener();
}
handleClick() {
this.setState(prevState => ({ counter: prevState.counter + 1 }));
}
render() {
return (
<div>
Count {this.state.counter} <button ref={this.buttonRef}>+</button>
</div>
);
}
}
ReactDOM.render(<CounterWithSyntheticEvents />, document.getElementById("container"));
class ReactSyntheticEvents extends HTMLElement {
connectedCallback() {
const mountPoint = document.createElement("div");
const shadow = this.attachShadow({ mode: "open" });
shadow.appendChild(mountPoint);
ReactDOM.render(<CounterWithSyntheticEvents />, mountPoint);
}
}
customElements.define("react-synthetic-events", ReactSyntheticEvents);
class ReactDOMEvents extends HTMLElement {
connectedCallback() {
const mountPoint = document.createElement("div");
const shadow = this.attachShadow({ mode: "open" });
shadow.appendChild(mountPoint);
ReactDOM.render(<CounterWithDOMEvents />, mountPoint);
}
}
customElements.define("react-dom-events", ReactDOMEvents);
<div id="container"></div>
<react-synthetic-events ></react-synthetic-events>
<react-dom-events ></react-dom-events>
The approach with the manual listeners binding works, but I want to avoid rewriting every single react component that is to be integrated.
Does anyone know about a quick fix I could do in order to have events propagated to the components ? (to make the 2nd case of the fiddle work)
I have heard of Polymer-react but haven't given it a try yet. And I'd like to not introduce another layer if possible.
Upvotes: 3
Views: 2508
Reputation: 53
I spent some time trying to find a fix or a workaround, and here is the result:
In the end, as a conclusion, we decided to use Web Components without the Shadow-DOM feature.
Upvotes: 2
Reputation: 7648
As per 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.
So answer is you only can take help of attaching event listeners yourself.
Upvotes: 1