Issue number: resolves #31315
What is the current behavior?
When an ion-refresher's host page is unmounted while the native refresher is still being set up, Ionic throws an uncaught TypeError from the gesture utility:
TypeError: Cannot read properties of undefined (reading '__zone_symbol__addEventListener')
at addEventListener (core/src/utils/gesture/listener.ts:21)
at Object.enable (core/src/utils/gesture/index.ts)
at Refresher.disabledChanged (core/src/components/refresher/refresher.tsx:125)
at Refresher.setupMDNativeRefresher (core/src/components/refresher/refresher.tsx:372)
setupMDNativeRefresher() and setupiOSNativeRefresher() both do:
this.gesture = (await import('../../utils/gesture')).createGesture({ el: this.scrollEl!, ... });
The dynamic import yields to the event loop. If the refresher is disconnected while it resolves, disconnectedCallback() (line 547-549) has already run this.scrollEl = undefined, so createGesture receives el: undefined, and the subsequent disabledChanged() โ gesture.enable(true) calls addEventListener(undefined, ...), which throws.
Because this happens inside an async method that nothing awaits, it surfaces as an unhandled promise rejection โ it cannot be caught by a framework error boundary; this crashes my app in playwright sometimes when components are mounted very quickly.
The ! non-null assertions on this.scrollEl are what hide this from TypeScript.
What is the new behavior?
If the refresher is disconnected while the gesture module is being imported, setup aborts quietly. No gesture is created, and no error is thrown.
Does this introduce a breaking change?
- Yes
- [ X] No