[FIX] components: cascading render after microtaskTick (makeChildFiber)

Co-authored-by: Samuel Degueldre <sad@odoo.com>
Co-authored-by: François Georis <fge@odoo.com>
This commit is contained in:
Lucas Perais (lpe)
2022-01-18 16:46:36 +01:00
committed by Aaron Bohy
parent 2a5f37cf4b
commit 374dbb2fd9
6 changed files with 111 additions and 46 deletions
+5 -5
View File
@@ -121,7 +121,7 @@ export class ComponentNode<T extends typeof Component = typeof Component>
async initiateRender(fiber: Fiber | MountFiber) {
this.fiber = fiber;
if (this.mounted.length) {
fiber.root.mounted.push(fiber);
fiber.root!.mounted.push(fiber);
}
const component = this.component;
try {
@@ -137,7 +137,7 @@ export class ComponentNode<T extends typeof Component = typeof Component>
async render() {
let current = this.fiber;
if (current && current.root.locked) {
if (current && current.root!.locked) {
await Promise.resolve();
// situation may have changed after the microtask tick
current = this.fiber;
@@ -167,7 +167,7 @@ export class ComponentNode<T extends typeof Component = typeof Component>
// a root fiber to a child fiber in the previous microtick, because it was
// embedded in a rendering coming from above, so the fiber will be rendered
// in the next microtick anyway, so we should not render it again.
if (this.fiber && (current || !fiber.parent)) {
if (this.fiber === fiber && (current || !fiber.parent)) {
this._render(fiber);
}
}
@@ -175,7 +175,7 @@ export class ComponentNode<T extends typeof Component = typeof Component>
_render(fiber: Fiber | RootFiber) {
try {
fiber.bdom = this.renderFn();
fiber.root.counter--;
fiber.root!.counter--;
} catch (e) {
handleError({ node: this, error: e });
}
@@ -218,7 +218,7 @@ export class ComponentNode<T extends typeof Component = typeof Component>
}
component.props = props;
this._render(fiber);
const parentRoot = parentFiber.root;
const parentRoot = parentFiber.root!;
if (this.willPatch.length) {
parentRoot.willPatch.push(fiber);
}
+2 -2
View File
@@ -30,7 +30,7 @@ function _handleError(node: ComponentNode | null, error: any, isFirstRound = fal
if (stopped) {
if (isFirstRound && fiber) {
fiber.root.counter--;
fiber.root!.counter--;
}
return true;
}
@@ -52,7 +52,7 @@ export function handleError(params: ErrorParams) {
current = current.parent;
} while (current);
fibersInError.set(fiber.root, error);
fibersInError.set(fiber.root!, error);
const handled = _handleError(node, error, true);
if (!handled) {
+4 -38
View File
@@ -3,46 +3,12 @@ import type { ComponentNode } from "./component_node";
import { fibersInError, handleError } from "./error_handling";
import { STATUS } from "./status";
/**
* Cleans on the root fiber the patch and willPatch fiber lists
* It is typically needed when the same root fiber needs to recycle on
* of its children or grandchildren's fiber.
*/
function cleanPatchableFiber(child: Fiber, root: RootFiber) {
const { willPatch, patched } = root;
let i = willPatch.indexOf(child);
if (i > -1) {
willPatch.splice(i, 1);
}
i = patched.indexOf(child);
if (i > -1) {
patched.splice(i, 1);
}
}
export function makeChildFiber(node: ComponentNode, parent: Fiber): Fiber {
let current = node.fiber;
if (current) {
// current is necessarily a rootfiber here
let root = parent.root;
const isSameRoot = current.root === root;
cancelFibers(root, current.children);
current.children = [];
current.parent = parent;
// only increment our rendering if we were not
// already accounted for, or that we have been rendered
// already (in which case our fiber was removed from the root rendering)
if (!isSameRoot || current.bdom) {
root.counter++;
}
if (isSameRoot) {
cleanPatchableFiber(current, root);
}
current.bdom = null;
current.root = root;
return current;
current.root = null;
}
return new Fiber(node, parent);
}
@@ -50,7 +16,7 @@ export function makeChildFiber(node: ComponentNode, parent: Fiber): Fiber {
export function makeRootFiber(node: ComponentNode): Fiber {
let current = node.fiber;
if (current) {
let root = current.root;
let root = current.root!;
root.counter -= cancelFibers(root, current.children);
current.children = [];
root.counter++;
@@ -92,7 +58,7 @@ function cancelFibers(root: any, fibers: Fiber[]): number {
export class Fiber {
node: ComponentNode;
bdom: BDom | null = null;
root: RootFiber;
root: RootFiber | null; // A Fiber that has been replaced by another has no root
parent: Fiber | null;
children: Fiber[] = [];
appliedToDom = false;
@@ -101,7 +67,7 @@ export class Fiber {
this.node = node;
this.parent = parent;
if (parent) {
const root = parent.root;
const root = parent.root!;
root.counter++;
this.root = root;
parent.children.push(this);
+1 -1
View File
@@ -25,7 +25,7 @@ export class Scheduler {
}
addFiber(fiber: Fiber) {
this.tasks.add(fiber.root);
this.tasks.add(fiber.root!);
if (!this.isRunning) {
this.start();
}