[FIX] component: destroy not yet mounted components (2)

Following 2922cee6ea

Previous commit was not correct: used children with a cancelled
fiber (for instance, with a new currentFiber) could be destroyed.
This commit fixes the issue differently, by directly detecting
children that are not used anymore (and not mounted), and destroy
them directly (no need to wait for willStart promise to be resolved
anymore).
This commit is contained in:
Aaron Bohy
2019-11-20 13:19:14 +01:00
committed by Géry Debongnie
parent 28ee790b3e
commit 2e3e8cd603
9 changed files with 86 additions and 45 deletions
+14
View File
@@ -60,6 +60,9 @@ interface Internal<T extends Env, Props> {
cmap: { [key: number]: number };
currentFiber: Fiber | null;
// parentLastFiberId is there to help the parent component to detect, among
// its children, those that are not used anymore and thus can be destroyed
parentLastFiberId: number;
boundHandlers: { [key: number]: any };
observer: Observer | null;
@@ -169,6 +172,7 @@ export class Component<T extends Env, Props extends {}> {
children: {},
cmap: {},
currentFiber: null,
parentLastFiberId: 0,
boundHandlers: {},
mountedCB: null,
willUnmountCB: null,
@@ -579,6 +583,16 @@ export class Component<T extends Env, Props extends {}> {
handlers: __owl__.boundHandlers,
fiber: fiber
});
// we iterate over the children to detect those that no longer belong to the
// current rendering: those ones, if not mounted yet, can (and have to) be
// destroyed right now, because they are not in the DOM, and thus we won't
// be notified later on (when patching), that they are removed from the DOM
for (let childKey in __owl__.children) {
let child = __owl__.children[childKey];
if (!child.__owl__.isMounted && child.__owl__.parentLastFiberId < fiber.id) {
child.destroy();
}
}
if (!vnode) {
throw new Error(`Rendering '${this.constructor.name}' did not return anything`);
}
+2 -1
View File
@@ -443,7 +443,7 @@ QWeb.addDirective({
);
ctx.addLine(`const fiber = w${componentID}.__owl__.currentFiber;`);
ctx.addLine(
`def${defID}.then(function () { if (fiber.isCompleted) { w${componentID}.destroy(); return; } const vnode = fiber.vnode; pvnode.sel = vnode.sel; ${createHook}});`
`def${defID}.then(function () { if (fiber.isCompleted) { return; } const vnode = fiber.vnode; pvnode.sel = vnode.sel; ${createHook}});`
);
if (registerCode) {
ctx.addLine(registerCode);
@@ -459,6 +459,7 @@ QWeb.addDirective({
ctx.addLine(`w${componentID}.__owl__.classObj=${classObj};`);
}
ctx.addLine(`w${componentID}.__owl__.parentLastFiberId = extra.fiber.id;`);
ctx.addLine(`sibling = w${componentID}.__owl__.currentFiber || sibling;`);
return true;
+4
View File
@@ -16,6 +16,9 @@ import { scheduler } from "./scheduler";
*/
export class Fiber {
static nextId: number = 1;
id: number = Fiber.nextId++;
// The force attribute determines if a rendering should bypass the `shouldUpdate`
// method potentially implemented by a component. It is usually set to false.
force: boolean;
@@ -101,6 +104,7 @@ export class Fiber {
oldFiber.child = null;
}
oldFiber.counter = 1; // re-initialize counter
oldFiber.id = Fiber.nextId++;
}
/**