Skip to content

Commit 0668f62

Browse files
fix(timeouts): clear timeouts
1 parent 1c89cf0 commit 0668f62

File tree

7 files changed

+72
-15
lines changed

7 files changed

+72
-15
lines changed

core/src/components/app/app.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ import { getIonMode } from '../../global/ionic-global';
1414
})
1515
export class App implements ComponentInterface {
1616
private focusVisible?: FocusVisibleUtility;
17+
private loadTimeout?: ReturnType<typeof setTimeout> | undefined;
1718

1819
@Element() el!: HTMLElement;
1920

2021
componentDidLoad() {
2122
if (Build.isBrowser) {
22-
rIC(async () => {
23+
this.rIC(async () => {
2324
const isHybrid = isPlatform(window, 'hybrid');
2425
if (!config.getBoolean('_testing')) {
2526
import('../../utils/tap-click').then((module) => module.startTapClick(config));
@@ -60,6 +61,12 @@ export class App implements ComponentInterface {
6061
}
6162
}
6263

64+
disconnectedCallback() {
65+
if (this.loadTimeout) {
66+
clearTimeout(this.loadTimeout);
67+
}
68+
}
69+
6370
/**
6471
* Used to set focus on an element that uses `ion-focusable`.
6572
* Do not use this if focusing the element as a result of a keyboard
@@ -78,6 +85,14 @@ export class App implements ComponentInterface {
7885
}
7986
}
8087

88+
private rIC(callback: () => void) {
89+
if ('requestIdleCallback' in window) {
90+
(window as any).requestIdleCallback(callback);
91+
} else {
92+
this.loadTimeout = setTimeout(callback, 32);
93+
}
94+
}
95+
8196
render() {
8297
const mode = getIonMode(this);
8398
return (
@@ -113,11 +128,3 @@ const needInputShims = () => {
113128

114129
return false;
115130
};
116-
117-
const rIC = (callback: () => void) => {
118-
if ('requestIdleCallback' in window) {
119-
(window as any).requestIdleCallback(callback);
120-
} else {
121-
setTimeout(callback, 32);
122-
}
123-
};

core/src/components/content/content.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ export class Content implements ComponentInterface {
188188
this.tabsElement = null;
189189
this.tabsLoadCallback = undefined;
190190
}
191+
192+
if (this.resizeTimeout) {
193+
clearTimeout(this.resizeTimeout);
194+
this.resizeTimeout = null;
195+
}
191196
}
192197

193198
/**

core/src/components/datetime/datetime.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export class Datetime implements ComponentInterface {
124124
private maxParts?: any;
125125
private todayParts!: DatetimeParts;
126126
private defaultParts!: DatetimeParts;
127+
private loadTimeout: ReturnType<typeof setTimeout> | undefined;
127128

128129
private prevPresentation: string | null = null;
129130

@@ -1077,6 +1078,9 @@ export class Datetime implements ComponentInterface {
10771078
this.clearFocusVisible();
10781079
this.clearFocusVisible = undefined;
10791080
}
1081+
if (this.loadTimeout) {
1082+
clearTimeout(this.loadTimeout);
1083+
}
10801084
}
10811085

10821086
/**
@@ -1175,7 +1179,7 @@ export class Datetime implements ComponentInterface {
11751179
*
11761180
* We schedule this after everything has had a chance to run.
11771181
*/
1178-
setTimeout(() => {
1182+
this.loadTimeout = setTimeout(() => {
11791183
this.ensureReadyIfVisible();
11801184
}, 100);
11811185

core/src/components/fab-list/fab-list.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { getIonMode } from '../../global/ionic-global';
1010
})
1111
export class FabList implements ComponentInterface {
1212
@Element() el!: HTMLIonFabElement;
13+
private activateTimeouts: ReturnType<typeof setTimeout>[] = [];
1314

1415
/**
1516
* If `true`, the fab list will show all fab buttons in the list.
@@ -18,12 +19,15 @@ export class FabList implements ComponentInterface {
1819

1920
@Watch('activated')
2021
protected activatedChanged(activated: boolean) {
22+
this.activateTimeouts.forEach(clearTimeout);
23+
this.activateTimeouts = [];
24+
2125
const fabs = Array.from(this.el.querySelectorAll('ion-fab-button'));
2226

2327
// if showing the fabs add a timeout, else show immediately
2428
const timeout = activated ? 30 : 0;
2529
fabs.forEach((fab, i) => {
26-
setTimeout(() => (fab.show = activated), i * timeout);
30+
this.activateTimeouts.push(setTimeout(() => (fab.show = activated), i * timeout));
2731
});
2832
}
2933

@@ -32,6 +36,11 @@ export class FabList implements ComponentInterface {
3236
*/
3337
@Prop() side: 'start' | 'end' | 'top' | 'bottom' = 'bottom';
3438

39+
disconnectedCallback() {
40+
this.activateTimeouts.forEach(clearTimeout);
41+
this.activateTimeouts = [];
42+
}
43+
3544
render() {
3645
const mode = getIonMode(this);
3746
return (

core/src/components/img/img.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { getIonMode } from '../../global/ionic-global';
1616
export class Img implements ComponentInterface {
1717
private io?: IntersectionObserver;
1818
private inheritedAttributes: Attributes = {};
19+
private loadTimeout: ReturnType<typeof setTimeout> | undefined;
1920

2021
@Element() el!: HTMLElement;
2122

@@ -56,7 +57,17 @@ export class Img implements ComponentInterface {
5657
this.addIO();
5758
}
5859

60+
disconnectedCallback() {
61+
if (this.loadTimeout) {
62+
clearTimeout(this.loadTimeout);
63+
}
64+
}
65+
5966
private addIO() {
67+
if (this.loadTimeout) {
68+
clearTimeout(this.loadTimeout);
69+
this.loadTimeout = undefined;
70+
}
6071
if (this.src === undefined) {
6172
return;
6273
}
@@ -82,7 +93,7 @@ export class Img implements ComponentInterface {
8293
this.io.observe(this.el);
8394
} else {
8495
// fall back to setTimeout for Safari and IE
85-
setTimeout(() => this.load(), 200);
96+
this.loadTimeout = setTimeout(() => this.load(), 200);
8697
}
8798
}
8899

core/src/components/label/label.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type { Color, StyleEventDetail } from '../../interface';
1818
})
1919
export class Label implements ComponentInterface {
2020
private inRange = false;
21+
private loadTimeout: ReturnType<typeof setTimeout> | undefined;
2122

2223
@Element() el!: HTMLElement;
2324

@@ -56,12 +57,18 @@ export class Label implements ComponentInterface {
5657

5758
componentDidLoad() {
5859
if (this.noAnimate) {
59-
setTimeout(() => {
60+
this.loadTimeout = setTimeout(() => {
6061
this.noAnimate = false;
6162
}, 1000);
6263
}
6364
}
6465

66+
disconnectedCallback() {
67+
if (this.loadTimeout) {
68+
clearTimeout(this.loadTimeout);
69+
}
70+
}
71+
6572
@Watch('color')
6673
colorChanged() {
6774
this.emitColor();

core/src/components/searchbar/searchbar.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export class Searchbar implements ComponentInterface {
3030
private originalIonInput?: EventEmitter<SearchbarInputEventDetail>;
3131
private inputId = `ion-searchbar-${searchbarIds++}`;
3232
private inheritedAttributes: Attributes = {};
33+
private loadTimeout: ReturnType<typeof setTimeout> | undefined;
34+
private clearTimeout: ReturnType<typeof setTimeout> | undefined;
3335

3436
/**
3537
* The value of the input when the textarea is focused.
@@ -288,11 +290,20 @@ export class Searchbar implements ComponentInterface {
288290
this.positionElements();
289291
this.debounceChanged();
290292

291-
setTimeout(() => {
293+
this.loadTimeout = setTimeout(() => {
292294
this.noAnimate = false;
293295
}, 300);
294296
}
295297

298+
disconnectedCallback() {
299+
if (this.loadTimeout) {
300+
clearTimeout(this.loadTimeout);
301+
}
302+
if (this.clearTimeout) {
303+
clearTimeout(this.clearTimeout);
304+
}
305+
}
306+
296307
private emitStyle() {
297308
this.ionStyle.emit({
298309
searchbar: true,
@@ -358,12 +369,15 @@ export class Searchbar implements ComponentInterface {
358369
* Clears the input field and triggers the control change.
359370
*/
360371
private onClearInput = async (shouldFocus?: boolean) => {
372+
if (this.clearTimeout) {
373+
clearTimeout(this.clearTimeout);
374+
}
361375
this.ionClear.emit();
362376

363377
return new Promise<void>((resolve) => {
364378
// setTimeout() fixes https://github.com/ionic-team/ionic-framework/issues/7527
365379
// wait for 4 frames
366-
setTimeout(() => {
380+
this.clearTimeout = setTimeout(() => {
367381
const value = this.getValue();
368382
if (value !== '') {
369383
this.value = '';

0 commit comments

Comments
 (0)