Skip to content

Commit 2d1a0aa

Browse files
committed
fix(runtime): dispatch queue events before willLoad
1 parent b05ae9c commit 2d1a0aa

File tree

6 files changed

+69
-12
lines changed

6 files changed

+69
-12
lines changed

src/declarations/runtime.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export interface HostRef {
9292
$onReadyPromise$?: Promise<any>;
9393
$onReadyResolve$?: (elm: any) => void;
9494
$vnode$?: d.VNode;
95+
$queuedListeners$?: [string, any][];
9596
$rmListeners$?: () => void;
9697
$modeName$?: string;
9798
}

src/runtime/host-listener.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import * as d from '../declarations';
22
import { BUILD } from '@build-conditionals';
3-
import { consoleError, doc, plt, supportsListenerOptions, win } from '@platform';
4-
import { LISTENER_FLAGS } from '@utils';
3+
import { doc, plt, supportsListenerOptions, win } from '@platform';
4+
import { HOST_FLAGS, LISTENER_FLAGS } from '@utils';
55

66

77
export const addEventListeners = (elm: d.HostElement, hostRef: d.HostRef, listeners: d.ComponentRuntimeHostListener[]) => {
8+
hostRef.$queuedListeners$ = hostRef.$queuedListeners$ || [];
89
const removeFns = listeners.map(([flags, name, method]) => {
910
const target = (BUILD.hostListenerTarget ? getHostListenerTarget(elm, flags) : elm);
1011
const handler = hostListenerProxy(hostRef, method);
@@ -18,15 +19,15 @@ export const addEventListeners = (elm: d.HostElement, hostRef: d.HostRef, listen
1819
const hostListenerProxy = (hostRef: d.HostRef, methodName: string) => {
1920
return (ev: Event) => {
2021
if (BUILD.lazyLoad) {
21-
if (hostRef.$lazyInstance$) {
22+
if (hostRef.$flags$ & HOST_FLAGS.isMethodsCallable) {
2223
// instance is ready, let's call it's member method for this event
23-
return hostRef.$lazyInstance$[methodName](ev);
24+
hostRef.$lazyInstance$[methodName](ev);
2425

2526
} else {
26-
return hostRef.$onReadyPromise$.then(() => hostRef.$lazyInstance$[methodName](ev)).catch(consoleError);
27+
hostRef.$queuedListeners$.push([methodName, ev]);
2728
}
2829
} else {
29-
return (hostRef.$hostElement$ as any)[methodName](ev);
30+
(hostRef.$hostElement$ as any)[methodName](ev);
3031
}
3132
};
3233
};

src/runtime/set-value.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const setValue = (ref: d.RuntimeRef, propName: string, newVal: any, cmpMe
2424

2525
if (!BUILD.lazyLoad || hostRef.$lazyInstance$) {
2626
// get an array of method names of watch functions to call
27-
if (BUILD.watchCallback && cmpMeta.$watchers$ && flags & HOST_FLAGS.isWatchReady) {
27+
if (BUILD.watchCallback && cmpMeta.$watchers$ && flags & HOST_FLAGS.isMethodsCallable) {
2828
const watchMethods = cmpMeta.$watchers$[propName];
2929

3030
if (watchMethods) {

src/runtime/test/listen.spec.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,57 @@ describe('listen', () => {
133133
expect(root).toEqualHtml(`
134134
<cmp-a>1,2,4,5,6</cmp-a>
135135
`);
136+
});
137+
138+
it('listen before load', async () => {
139+
let log = '';
140+
@Component({ tag: 'cmp-a'})
141+
class CmpA {
142+
@Listen('event')
143+
onEvent(ev: CustomEvent<string>) {
144+
log += ev.detail;
145+
}
146+
147+
connectedCallback() {
148+
log += 'connectedCallback ';
149+
}
150+
151+
componentWillLoad() {
152+
log += 'componentWillLoad ';
153+
}
136154

155+
componentDidLoad() {
156+
log += 'componentDidLoad ';
157+
}
158+
159+
render() {
160+
return `${log}`;
161+
}
162+
}
163+
164+
const { doc, waitForChanges } = await newSpecPage({
165+
components: [CmpA],
166+
html: '',
167+
});
168+
169+
const a = doc.createElement('cmp-a');
170+
doc.body.appendChild(a);
171+
172+
a.dispatchEvent(new CustomEvent('event', {
173+
detail: 'event1 '
174+
}));
175+
a.dispatchEvent(new CustomEvent('event', {
176+
detail: 'event2 '
177+
}));
178+
a.dispatchEvent(new CustomEvent('event', {
179+
detail: 'event3 '
180+
}));
181+
182+
await Promise.resolve();
183+
expect(log).toEqualHtml('');
184+
185+
await waitForChanges();
186+
expect(log).toEqualHtml(`connectedCallback event1 event2 event3 componentWillLoad componentDidLoad`);
137187
});
188+
138189
});

src/runtime/update-component.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import { HYDRATED_CLASS, PLATFORM_FLAGS } from './runtime-constants';
77
import { renderVdom } from './vdom/vdom-render';
88

99

10-
export const safeCall = async (instance: any, method: string) => {
10+
export const safeCall = async (instance: any, method: string, arg?: any) => {
1111
if (instance && instance[method]) {
1212
try {
13-
await instance[method]();
13+
await instance[method](arg);
1414
} catch (e) {
1515
consoleError(e);
1616
}
@@ -23,8 +23,12 @@ export const scheduleUpdate = async (elm: d.HostElement, hostRef: d.HostRef, cmp
2323
}
2424
const instance = BUILD.lazyLoad ? hostRef.$lazyInstance$ : elm as any;
2525
if (isInitialLoad) {
26-
if (BUILD.watchCallback) {
27-
hostRef.$flags$ |= HOST_FLAGS.isWatchReady;
26+
if (BUILD.watchCallback || BUILD.hostListener) {
27+
hostRef.$flags$ |= HOST_FLAGS.isMethodsCallable;
28+
}
29+
if (BUILD.hostListener && hostRef.$queuedListeners$) {
30+
hostRef.$queuedListeners$.forEach(([methodName, event]) => safeCall(instance, methodName, event));
31+
hostRef.$queuedListeners$ = null;
2832
}
2933
emitLifecycleEvent(elm, 'componentWillLoad');
3034
if (BUILD.cmpWillLoad) {

src/utils/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const enum HOST_FLAGS {
4343
isQueuedForUpdate = 1 << 4,
4444
hasInitializedComponent = 1 << 5,
4545
hasLoadedComponent = 1 << 6,
46-
isWatchReady = 1 << 7,
46+
isMethodsCallable = 1 << 7,
4747
}
4848

4949
export const enum CMP_FLAGS {

0 commit comments

Comments
 (0)