From b81b0d14258d7b8caf028e6cfe81772ed2f5f119 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 10 Apr 2023 14:40:54 -0400 Subject: [PATCH] fix(menu): refs are not destroyed on unmount (#27141) ## What is the current behavior? Issue URL: resolves https://github.com/ionic-team/ionic-framework/issues/24907 `ion-menu` currently clears the `menuInnerEl` and `backdropEl` refs created by Stencil when `disconnectedCallback` is fired. If the `ion-menu` component is re-mounted but _not_ re-rendered, those refs will still be `undefined` when the `open` method is called, resulting in the linked issue. Note that if the `ion-menu` re-renders before `open` is called then this issue does not reproduce. This clearing behavior was added ~6 years ago before we utilized Stencil refs: https://github.com/ionic-team/ionic-framework/blob/687b37ad3e3237b874473817bb7b59143ac113ce/packages/core/src/components/menu/menu.tsx#L136-L137 During this time we had to manually create and clear the element references. Several years later we moved to using Stencil refs, but we did not remove the logic that clears the refs: https://github.com/ionic-team/ionic-framework/commit/d83d8eed12b0b7e852feffd77d51c9f5a92e6640 ## What is the new behavior? - Menu no longer sets `menuInnerEl` and `backdropEl` to `undefined` in `disconnectedCallback`. - The `close` method is called so that the state is reset prior to the menu being re-added. I observed that without this, the animation to re-present a menu did not work correctly. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information --- core/src/components/menu/menu.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/core/src/components/menu/menu.tsx b/core/src/components/menu/menu.tsx index ff0dd4e202..f89a0cede9 100644 --- a/core/src/components/menu/menu.tsx +++ b/core/src/components/menu/menu.tsx @@ -241,7 +241,16 @@ export class Menu implements ComponentInterface, MenuI { this.updateState(); } - disconnectedCallback() { + async disconnectedCallback() { + /** + * The menu should be closed when it is + * unmounted from the DOM. + * This is an async call, so we need to wait for + * this to finish otherwise contentEl + * will not have MENU_CONTENT_OPEN removed. + */ + await this.close(false); + this.blocker.destroy(); menuController._unregister(this); if (this.animation) { @@ -253,7 +262,7 @@ export class Menu implements ComponentInterface, MenuI { } this.animation = undefined; - this.contentEl = this.backdropEl = this.menuInnerEl = undefined; + this.contentEl = undefined; } @Listen('ionSplitPaneVisible', { target: 'body' })