class MountableWatcher extends HTMLElement { constructor() { console.log("creating component"); super(); } connectedCallback() { this.render(); } disconnectedCallback() { console.log("disconnected"); this.dispatchEvent(new CustomEvent("unmounted", { bubbles: false })); } attributeChangedCallback(attrName, oldVal, newVal) { if (attrName === "onunmount" && oldVal !== newVal) { if (newVal === null) { this.onunmount = null; } else { } } } static get observedAttributes() { return ["onunmount"]; } get onunmount() { return this._onUnmountFn; } set onunmount(handler) { if (this._onUnmountFn) { this.removeEventListener("unmount", this._onCheckFn); this._onUnmountFn = null; } if (typeof handler === "function") { this._onUnmountFn = handler; this.addEventListener("unmount", this._onCheckFn); } } render() { this.innerHTML = "

Hello from watcher

"; } } customElements.define("mountable-watcher", MountableWatcher); // React Elm Component var ElmComponent = React.createClass({ initialize: function(node) { if (node === null) return; var app = this.props.src.embed(node, this.props.flags); if (typeof this.props.ports !== "undefined") { this.props.ports(app.ports); } }, shouldComponentUpdate: function(prevProps) { return false; }, render: function() { return React.createElement("div", { ref: this.initialize }); } }); var node = document.getElementById("elm-app"); function remount(el) { ReactDOM.unmountComponentAtNode(el); ReactDOM.render(React.createElement(ElmComponent, { src: Elm.Main }), el); } document.getElementById("button").addEventListener("click", function() { remount(node); });