Skip to content

Commit dffc5bb

Browse files
fix(runtime): handle lazy-instance promises for connected & disconnected 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 <47483144+tanner-reits@users.noreply.github.com> * Apply suggested SNC changes Co-authored-by: Tanner Reits <47483144+tanner-reits@users.noreply.github.com> --------- Co-authored-by: Tanner Reits <47483144+tanner-reits@users.noreply.github.com>
1 parent 8ae64f2 commit dffc5bb

File tree

3 files changed

+95
-8
lines changed

3 files changed

+95
-8
lines changed

src/runtime/connected-callback.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,11 @@ export const connectedCallback = (elm: d.HostElement) => {
106106
addHostEventListeners(elm, hostRef, cmpMeta.$listeners$, false);
107107

108108
// fire off connectedCallback() on component instance
109-
fireConnectedCallback(hostRef.$lazyInstance$);
109+
if (hostRef?.$lazyInstance$) {
110+
fireConnectedCallback(hostRef.$lazyInstance$);
111+
} else if (hostRef?.$onReadyPromise$) {
112+
hostRef.$onReadyPromise$.then(() => fireConnectedCallback(hostRef.$lazyInstance$));
113+
}
110114
}
111115

112116
endConnected();

src/runtime/disconnected-callback.ts

+16-7
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ import type * as d from '../declarations';
55
import { PLATFORM_FLAGS } from './runtime-constants';
66
import { safeCall } from './update-component';
77

8-
export const disconnectedCallback = (elm: d.HostElement) => {
8+
const disconnectInstance = (instance: any) => {
9+
if (BUILD.lazyLoad && BUILD.disconnectedCallback) {
10+
safeCall(instance, 'disconnectedCallback');
11+
}
12+
if (BUILD.cmpDidUnload) {
13+
safeCall(instance, 'componentDidUnload');
14+
}
15+
};
16+
17+
export const disconnectedCallback = async (elm: d.HostElement) => {
918
if ((plt.$flags$ & PLATFORM_FLAGS.isTmpDisconnected) === 0) {
1019
const hostRef = getHostRef(elm);
11-
const instance: any = BUILD.lazyLoad ? hostRef.$lazyInstance$ : elm;
1220

1321
if (BUILD.hostListener) {
1422
if (hostRef.$rmListeners$) {
@@ -17,11 +25,12 @@ export const disconnectedCallback = (elm: d.HostElement) => {
1725
}
1826
}
1927

20-
if (BUILD.lazyLoad && BUILD.disconnectedCallback) {
21-
safeCall(instance, 'disconnectedCallback');
22-
}
23-
if (BUILD.cmpDidUnload) {
24-
safeCall(instance, 'componentDidUnload');
28+
if (!BUILD.lazyLoad) {
29+
disconnectInstance(elm);
30+
} else if (hostRef?.$lazyInstance$) {
31+
disconnectInstance(hostRef.$lazyInstance$);
32+
} else if (hostRef?.$onReadyPromise$) {
33+
hostRef.$onReadyPromise$.then(() => disconnectInstance(hostRef.$lazyInstance$));
2534
}
2635
}
2736
};

src/runtime/test/lifecycle-sync.spec.tsx

+74
Original file line numberDiff line numberDiff line change
@@ -346,4 +346,78 @@ describe('lifecycle sync', () => {
346346
</cmp-root>
347347
`);
348348
});
349+
350+
it('call disconnectedCallback even if the element is immediately removed', async () => {
351+
let connected = 0;
352+
let disconnected = 0;
353+
354+
@Component({ tag: 'cmp-a' })
355+
class CmpA {
356+
connectedCallback() {
357+
connected++;
358+
}
359+
360+
disconnectedCallback() {
361+
disconnected++;
362+
}
363+
364+
render() {
365+
return <Host></Host>;
366+
}
367+
}
368+
369+
const { doc, waitForChanges } = await newSpecPage({
370+
components: [CmpA],
371+
});
372+
373+
const a1 = doc.createElement('cmp-a');
374+
doc.body.appendChild(a1);
375+
a1.remove();
376+
377+
await waitForChanges();
378+
379+
expect(connected).toEqual(1);
380+
expect(disconnected).toEqual(1);
381+
});
382+
383+
it('calls disconnect and connect when an element is moved in the DOM', async () => {
384+
let connected = 0;
385+
let disconnected = 0;
386+
387+
@Component({ tag: 'cmp-a' })
388+
class CmpA {
389+
connectedCallback() {
390+
connected++;
391+
}
392+
393+
disconnectedCallback() {
394+
disconnected++;
395+
}
396+
397+
render() {
398+
return <Host></Host>;
399+
}
400+
}
401+
402+
const { doc, waitForChanges } = await newSpecPage({
403+
components: [CmpA],
404+
});
405+
406+
const cmp = doc.createElement('cmp-a');
407+
doc.body.appendChild(cmp);
408+
409+
await waitForChanges();
410+
411+
// Create a container we will move the component to
412+
const container = doc.createElement('div');
413+
doc.body.appendChild(container);
414+
415+
// Move the component
416+
container.appendChild(cmp);
417+
418+
container.remove();
419+
420+
expect(connected).toEqual(2);
421+
expect(disconnected).toEqual(2);
422+
});
349423
});

0 commit comments

Comments
 (0)