mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[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:
committed by
Aaron Bohy
parent
2a5f37cf4b
commit
374dbb2fd9
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user