mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] component: missing renderings in some cases
This commit is contained in:
@@ -107,8 +107,14 @@ export function component<P extends object>(
|
|||||||
|
|
||||||
const parentFiber = ctx.fiber!;
|
const parentFiber = ctx.fiber!;
|
||||||
if (node) {
|
if (node) {
|
||||||
const currentProps = node.component.props[TARGET];
|
let shouldRender = node.forceNextRender;
|
||||||
if (parentFiber.deep || arePropsDifferent(currentProps, props)) {
|
if (shouldRender) {
|
||||||
|
node.forceNextRender = false;
|
||||||
|
} else {
|
||||||
|
const currentProps = node.component.props[TARGET];
|
||||||
|
shouldRender = parentFiber.deep || arePropsDifferent(currentProps, props);
|
||||||
|
}
|
||||||
|
if (shouldRender) {
|
||||||
node.updateAndRender(props, parentFiber);
|
node.updateAndRender(props, parentFiber);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -143,6 +149,7 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
|
|||||||
component: Component<P, E>;
|
component: Component<P, E>;
|
||||||
bdom: BDom | null = null;
|
bdom: BDom | null = null;
|
||||||
status: STATUS = STATUS.NEW;
|
status: STATUS = STATUS.NEW;
|
||||||
|
forceNextRender: boolean = false;
|
||||||
|
|
||||||
renderFn: Function;
|
renderFn: Function;
|
||||||
parent: ComponentNode | null;
|
parent: ComponentNode | null;
|
||||||
|
|||||||
@@ -43,7 +43,15 @@ function cancelFibers(fibers: Fiber[]): number {
|
|||||||
let result = 0;
|
let result = 0;
|
||||||
for (let fiber of fibers) {
|
for (let fiber of fibers) {
|
||||||
fiber.node.fiber = null;
|
fiber.node.fiber = null;
|
||||||
if (!fiber.bdom) {
|
if (fiber.bdom) {
|
||||||
|
// if fiber has been rendered, this means that the component props have
|
||||||
|
// been updated. however, this fiber will not be patched to the dom, so
|
||||||
|
// it could happen that the next render compare the current props with
|
||||||
|
// the same props, and skip the render completely. With the next line,
|
||||||
|
// we kindly request the component code to force a render, so it works as
|
||||||
|
// expected.
|
||||||
|
fiber.node.forceNextRender = true;
|
||||||
|
} else {
|
||||||
result++;
|
result++;
|
||||||
}
|
}
|
||||||
result += cancelFibers(fiber.children);
|
result += cancelFibers(fiber.children);
|
||||||
|
|||||||
@@ -1222,6 +1222,28 @@ exports[`rendering component again in next microtick 2`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`rendering parent twice, with different props on child and stuff 1`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return component(\`Child\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`rendering parent twice, with different props on child and stuff 2`] = `
|
||||||
|
"function anonymous(bdom, helpers
|
||||||
|
) {
|
||||||
|
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
||||||
|
|
||||||
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
return text(ctx['props'].value);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`t-foreach with dynamic async component 1`] = `
|
exports[`t-foreach with dynamic async component 1`] = `
|
||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -3189,6 +3189,71 @@ test("Cascading renders after microtaskTick", async () => {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("0123 _ 0123");
|
expect(fixture.innerHTML).toBe("0123 _ 0123");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("rendering parent twice, with different props on child and stuff", async () => {
|
||||||
|
class Child extends Component {
|
||||||
|
static template = xml`<t t-esc="props.value"/>`;
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component {
|
||||||
|
static template = xml`<Child value="state.value"/>`;
|
||||||
|
static components = { Child };
|
||||||
|
state = useState({ value: 1 });
|
||||||
|
setup() {
|
||||||
|
useLogLifecycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = await mount(Parent, fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("1");
|
||||||
|
expect([
|
||||||
|
"Parent:setup",
|
||||||
|
"Parent:willStart",
|
||||||
|
"Parent:willRender",
|
||||||
|
"Child:setup",
|
||||||
|
"Child:willStart",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
"Child:mounted",
|
||||||
|
"Parent:mounted",
|
||||||
|
]).toBeLogged();
|
||||||
|
|
||||||
|
parent.state.value = 2;
|
||||||
|
// wait for child to be rendered
|
||||||
|
await nextMicroTick();
|
||||||
|
await nextMicroTick();
|
||||||
|
await nextMicroTick();
|
||||||
|
await nextMicroTick();
|
||||||
|
expect([
|
||||||
|
"Parent:willRender",
|
||||||
|
"Child:willUpdateProps",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
]).toBeLogged();
|
||||||
|
expect(fixture.innerHTML).toBe("1");
|
||||||
|
|
||||||
|
// trigger a render, but keep the props for child the same
|
||||||
|
parent.render();
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("2");
|
||||||
|
expect([
|
||||||
|
"Parent:willRender",
|
||||||
|
"Child:willUpdateProps",
|
||||||
|
"Parent:rendered",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
|
"Parent:willPatch",
|
||||||
|
"Child:willPatch",
|
||||||
|
"Child:patched",
|
||||||
|
"Parent:patched",
|
||||||
|
]).toBeLogged();
|
||||||
|
});
|
||||||
|
|
||||||
// test.skip("components with shouldUpdate=false", async () => {
|
// test.skip("components with shouldUpdate=false", async () => {
|
||||||
// const state = { p: 1, cc: 10 };
|
// const state = { p: 1, cc: 10 };
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user