[FIX] component: fix issue with crash caused by async rendering

This may (or may not?) closes #85
This commit is contained in:
Géry Debongnie
2019-05-06 14:23:29 +02:00
parent 91896942dd
commit ba506be58d
3 changed files with 56 additions and 2 deletions
+1 -1
View File
@@ -200,7 +200,7 @@ a owl component:
| ------------------------------------------------ | --------------------------------------- |
| **[constructor](#constructor)** | constructor |
| **[willStart](#willStart)** | async, before first rendering |
| **[mounted](#mounted)** | when component is render and in DOM |
| **[mounted](#mounted)** | just after component is rendered and added to the DOM |
| **[willUpdateProps](#willupdatepropsnextprops)** | async, before props update |
| **[willPatch](#willpatch)** | just before the DOM is patched |
| **[patched](#patchedsnapshot)** | just after the DOM is patched |
+2 -1
View File
@@ -248,7 +248,8 @@ export class Component<
const renderVDom = this._render(force, patchQueue);
const renderId = this.__owl__.renderId;
const vnode = await renderVDom;
if (renderId === this.__owl__.renderId) {
if (this.__owl__.isMounted && renderId === this.__owl__.renderId) {
// we only update the vnode and the actual DOM if no other rendering
// occurred between now and when the render method was initially called.
if (shouldCallPatchHooks) {
+53
View File
@@ -1645,6 +1645,59 @@ describe("async rendering", () => {
"<div><span>a2</span><span>b2</span></div>"
);
});
test.only("properly behave when destroyed/unmounted while rendering ", async () => {
let def = Promise.resolve();
class Child extends Widget {
inlineTemplate = `<div><t t-widget="SubChild"/></div>`;
widgets = { SubChild };
mounted() {
// from now on, each rendering in child widget will be delayed (see
// _render)
def = makeDeferred();
}
async _render(f, p) {
const result = await super._render(f, p);
await def;
return result;
}
}
class SubChild extends Widget {
willPatch() {
throw new Error("Should not happen!");
}
patched() {
throw new Error("Should not happen!");
}
}
class Parent extends Widget {
inlineTemplate = `
<div><t t-if="state.flag"><t t-widget="Child" t-props="{val: state.val}"/></t></div>`;
widgets = { Child };
state = { flag: true, val: "Framboise Lindemans" };
}
const parent = new Parent(env);
await parent.mount(fixture);
expect(fixture.innerHTML).toBe("<div><div><div></div></div></div>");
// this change triggers a rendering of the parent. This rendering is delayed,
// because child is now waiting for def to be resolved
parent.state.val = "Framboise Girardin";
await nextTick();
// with this, we remove child, and childchild, even though it is not finished
// rendering from previous changes
parent.state.flag = false;
await nextTick();
// we now resolve def, so the child rendering is now complete.
(<any>def).resolve();
await nextTick();
expect(fixture.innerHTML).toBe("<div></div>");
});
});
describe("updating environment", () => {