mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] component: fix issue with crash caused by async rendering
This may (or may not?) closes #85
This commit is contained in:
+1
-1
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
Reference in New Issue
Block a user