Skip to content

Commit

Permalink
fix(flow-react): avoid Flow-React portal outlet removal conflicts
Browse files Browse the repository at this point in the history
Some routing cases in hybrid Flow layout + React view applications could produce DOM tree conflicts from Flow server-side changes and React client-side portal removal happening simultaneously. This could throw DOM `NotFoundError` in the browser. This change introduces a dedicated DOM element for React portal outlet, which allows to avoid the error.

Fixes vaadin/hilla#3002
  • Loading branch information
platosha committed Dec 20, 2024
1 parent d789970 commit 5de9f48
Showing 1 changed file with 10 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ export abstract class ReactAdapterElement extends HTMLElement {

#unmountComplete = Promise.resolve();

#portalOutlet: HTMLElement | null = null;

constructor() {
super();
this.#renderHooks = {
Expand All @@ -151,9 +153,14 @@ export abstract class ReactAdapterElement extends HTMLElement {
}

public async connectedCallback() {
if (this.#portalOutlet === null) {
this.#portalOutlet = document.createElement('flow-portal-outlet');
this.#portalOutlet.style.display = 'contents';
this.appendChild(this.#portalOutlet);
}
await this.#unmountComplete;
this.#rendering = createElement(this.#Wrapper);
const createNewRoot = this.dispatchEvent(new CustomEvent('flow-portal-add', {
const createNewRoot = this.#portalOutlet!.dispatchEvent(new CustomEvent('flow-portal-add', {
bubbles: true,
cancelable: true,
composed: true,
Expand All @@ -167,7 +174,7 @@ export abstract class ReactAdapterElement extends HTMLElement {
return;
}

this.#root = createRoot(this);
this.#root = createRoot(this.#portalOutlet!);
this.#maybeRenderRoot();
this.#root.render(this.#rendering);
}
Expand All @@ -187,7 +194,7 @@ export abstract class ReactAdapterElement extends HTMLElement {
}

public async disconnectedCallback() {
this.dispatchEvent(new CustomEvent('flow-portal-remove', {
this.#portalOutlet!.dispatchEvent(new CustomEvent('flow-portal-remove', {
bubbles: true,
cancelable: true,
composed: true,
Expand Down

0 comments on commit 5de9f48

Please sign in to comment.