[REF] hooks: better implementation of onMounted/onWillUnmount

This commit is contained in:
Géry Debongnie
2019-09-28 21:11:32 +02:00
parent 090880f478
commit f6820bb8ac
4 changed files with 23 additions and 14 deletions
+9 -4
View File
@@ -84,6 +84,7 @@ interface Internal<T extends Env, Props> {
observer: Observer | null; observer: Observer | null;
render: CompiledTemplate | null; render: CompiledTemplate | null;
mountedHandlers: { [key: number]: Function }; mountedHandlers: { [key: number]: Function };
willUnmountCB: Function | null;
classObj: { [key: string]: boolean } | null; classObj: { [key: string]: boolean } | null;
refs: { [key: string]: Component<T, any> | HTMLElement | undefined } | null; refs: { [key: string]: Component<T, any> | HTMLElement | undefined } | null;
} }
@@ -185,6 +186,7 @@ export class Component<T extends Env, Props extends {}> {
currentFiber: null, currentFiber: null,
boundHandlers: {}, boundHandlers: {},
mountedHandlers: {}, mountedHandlers: {},
willUnmountCB: null,
observer: null, observer: null,
render: null, render: null,
classObj: null, classObj: null,
@@ -481,19 +483,22 @@ export class Component<T extends Env, Props extends {}> {
} }
__owl__.isMounted = true; __owl__.isMounted = true;
const handlers = __owl__.mountedHandlers; const handlers = __owl__.mountedHandlers;
for (let key in handlers) {
handlers[key]();
}
try { try {
this.mounted(); this.mounted();
for (let key in handlers) {
handlers[key]();
}
} catch (e) { } catch (e) {
errorHandler(e, this); errorHandler(e, this);
} }
} }
__callWillUnmount() { __callWillUnmount() {
this.willUnmount();
const __owl__ = this.__owl__; const __owl__ = this.__owl__;
if (__owl__.willUnmountCB) {
__owl__.willUnmountCB();
}
this.willUnmount();
__owl__.isMounted = false; __owl__.isMounted = false;
const children = __owl__.children; const children = __owl__.children;
for (let id in children) { for (let id in children) {
+12 -10
View File
@@ -33,13 +33,11 @@ export function useState<T>(state: T): T {
* Mounted hook. The callback will be called when the current component is * Mounted hook. The callback will be called when the current component is
* mounted. Note that the component mounted method is called first. * mounted. Note that the component mounted method is called first.
*/ */
let nextID = 1;
export function onMounted(cb) { export function onMounted(cb) {
const component: Component<any, any> = Component._current; const component: Component<any, any> = Component._current;
const current = component.mounted; component.__owl__.mountedHandlers[`h${nextID++}`] = cb;
component.mounted = function() {
current.call(component);
cb();
};
} }
/** /**
@@ -48,11 +46,15 @@ export function onMounted(cb) {
*/ */
export function onWillUnmount(cb) { export function onWillUnmount(cb) {
const component: Component<any, any> = Component._current; const component: Component<any, any> = Component._current;
const current = component.willUnmount; if (component.__owl__.willUnmountCB) {
component.willUnmount = function() { const current = component.__owl__.willUnmountCB;
cb(); component.__owl__.willUnmountCB = function() {
current.call(component); cb.call(component);
}; current.call(component);
};
} else {
component.__owl__.willUnmountCB = cb;
}
} }
/** /**
View File
+2
View File
@@ -61,6 +61,8 @@ describe("hooks", () => {
} }
const component = new MyComponent(env); const component = new MyComponent(env);
await component.mount(fixture); await component.mount(fixture);
expect(component).not.toHaveProperty("mounted");
expect(component).not.toHaveProperty("willUnmount");
expect(fixture.innerHTML).toBe("<div>hey</div>"); expect(fixture.innerHTML).toBe("<div>hey</div>");
expect(steps).toEqual(["mounted"]); expect(steps).toEqual(["mounted"]);
component.unmount(); component.unmount();