Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: disconnectedCallback is not always called when it should be #4070

Closed
3 tasks done
joewoodhouse opened this issue Feb 17, 2023 · 4 comments
Closed
3 tasks done

bug: disconnectedCallback is not always called when it should be #4070

joewoodhouse opened this issue Feb 17, 2023 · 4 comments
Labels
Bug: Validated This PR or Issue is verified to be a bug within Stencil

Comments

@joewoodhouse
Copy link
Contributor

Prerequisites

Stencil Version

3.0.1

Current Behavior

There are some very simple circumstances where a component's disconnectedCallback will not be called when it should be (i.e. when the element is moved or removed). This can lead to resource leaks if the user is attaching event listeners or doing other operations in their connectedCallback that they then hope to tidy up in the disconnectedCallback (e.g. adding event listeners).

Expected Behavior

The disconnectedCallback callback should be called consistently, inline with how a "native" CustomElement behaves.

System Info

No response

Steps to Reproduce

Simple adding then removing of element

const elm = document.createElement('my-stencil-component');

document.body.appendChild(elm);
// connectedCallback is now called

elm.remove();
// disconnectedCallback will NOT be called

Moving an element

const elm = document.createElement('my-stencil-component');

document.body.appendChild(elm);
// connectedCallback is now called

// Create another element to move ours into
const container = document.createElement('div');
document.body.appendChild(container);

// Move our element
container.appendChild(elm);
// First connectedCallback and disconnectedCallback *should* be called, but are not.

container.remove()
// disconnectedCallback is NOT called

The reproduction repository performs the above steps, but also does so alongside a "native" non-Stencil custom element, to show the "correct" behaviour. When you run the repository, every 1 second the above operations are run against both a "native" and a stencil component, and the counters for connected and disconnected callbacks are displayed. You will see that the native element performs correctly, calling connectedCallback and disconnectedCallback 2 times each. However the Stencil element only calls connectedCallback once per cycle, and NEVER calls disconnectedCallback.

Code Reproduction URL

https://github.com/joewoodhouse/stencil-disconnectedcallback-issues

Additional Information

Again I found this issue whilst debugging huge resource leaks in our Ionic/Capacitor application which is causing our app to crash regularly for our users after moderate usage.

The issue I believe is in the Stencil's patchdisconnectedCallback. The platform of course does call this method, it's just the patched method in the Stencil runtime does then not call the components own implementation.

https://github.com/ionic-team/stencil/blob/main/src/runtime/disconnected-callback.ts#L11

Here the code detects that we're lazy loading and takes the instance to be hostRef.$lazyIntance$. However in the cases above, $lazyInstance$ will not yet be set as lazy loading hasn't completed. The code in this case should wait for hostRef.$onReadyPromise$ to resolve before attempting to call the disconnectedCallback. I will provide a PR with this version shortly.

Note in all the above I have focused on disconnectedCallback but it should also all apply for componentDidUnload which is called (or in this case not) at the same time.

@rwaskiewicz
Copy link
Contributor

Thanks @joewoodhouse!

I've confirmed this isn't working as expected based on the reproduction case and am going to get this labeled so that the team and I can discuss

@rwaskiewicz rwaskiewicz added the Bug: Validated This PR or Issue is verified to be a bug within Stencil label Mar 1, 2023
@ionitron-bot ionitron-bot bot removed the triage label Mar 1, 2023
@rwaskiewicz rwaskiewicz removed their assignment Mar 1, 2023
joewoodhouse added a commit to joewoodhouse/stencil that referenced this issue Mar 10, 2023
joewoodhouse added a commit to joewoodhouse/stencil that referenced this issue Mar 10, 2023
@dobrek
Copy link

dobrek commented May 24, 2023

any updates on this issue? is this proposed fix taken into consideration to be merged soon?

github-merge-queue bot pushed a commit that referenced this issue Jul 26, 2023
…ted callbacks (#4072)

* Adds a two unit tests highlighting #4070

* Adds proposed fix for #4070

* Run prettier

* Add equivalent waiting for $ in connected callback

* Apply suggested SNC changes

Co-authored-by: Tanner Reits <[email protected]>

* Apply suggested SNC changes

Co-authored-by: Tanner Reits <[email protected]>

---------

Co-authored-by: Tanner Reits <[email protected]>
@tanner-reits
Copy link
Contributor

@joewoodhouse 's PR to resolve this issue has been merged and will be a part of the next Stencil release!

@tanner-reits
Copy link
Contributor

This was resolved in Stencil v4.0.3. Please re-open this issue if you are still experiencing issues after updating.

github-merge-queue bot pushed a commit to ionic-team/ionic-framework that referenced this issue Aug 24, 2023
Issue number: resolves #28030

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

`ion-menu` registers itself with the menu controller when
`connectedCallback` fires and then unregisters itself when
`disconnectedCallback` fires. When the menu was removed from the DOM,
`disconnectedCallback` was not always being fired due to
ionic-team/stencil#4070.

`ion-menu-button` checks to see if it should be visible by grabbing the
current menu in
https://github.com/ionic-team/ionic-framework/blob/314055cf7a66a58e4e88c22e6e755fadd494ed70/core/src/components/menu-button/menu-button.tsx#L74.

Since `disconnectedCallback` was not being fired, `ion-menu-button`
would still find the menu even when it was no longer in the DOM. In this
case, the menu was not being unregistered due to `disconnectedCallback`
not firing.

When the linked Stencil bug was resolved in Stencil 4.0.3, the menu
button started to disappear. This is happening because
`disconnectedCallback` is now correctly called when the menu is removed
from the DOM. Since `disconnectedCallback` is called, the menu is
un-registered from the menu controller, and the menu button can no
longer find it.

However, this revealed a long-standing bug where re-adding the menu
would not fire `ionMenuChange` again. As a result, the menu button
remained hidden.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- The menu now fires `ionMenuChange` on `connectedCallback` as long as
`componentDidLoad` has already been run.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Dev build: `7.3.2-dev.11692803611.15c1bc87`

---------

Co-authored-by: Sean Perkins <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug: Validated This PR or Issue is verified to be a bug within Stencil
Projects
None yet
Development

No branches or pull requests

4 participants