mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] component: properly set currentFiber to null in all cases
Whenever a rendering is completed, we need to reset the currentFiber to null to make sure all subsequent renderings will not be confused. However, the way it was done before this commit was wrong in a specific situation: we resetted the currentFiber to null in the patch method. The idea was that this method was called every time the component completes a rendering. But this is not true: it can happen that a component is unmounted and remounted without changes. Then the component will be patched, but if there is no change, it will not call recursively the patched methods of its children. So, we need to choose a better place to reset it to null. closes #454
This commit is contained in:
@@ -451,6 +451,7 @@ export class Component<T extends Env, Props extends {}> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
__owl__.isMounted = true;
|
__owl__.isMounted = true;
|
||||||
|
__owl__.currentFiber = null;
|
||||||
try {
|
try {
|
||||||
this.mounted();
|
this.mounted();
|
||||||
if (__owl__.mountedCB) {
|
if (__owl__.mountedCB) {
|
||||||
@@ -526,7 +527,6 @@ export class Component<T extends Env, Props extends {}> {
|
|||||||
const __owl__ = this.__owl__;
|
const __owl__ = this.__owl__;
|
||||||
const target = __owl__.vnode || document.createElement(vnode.sel!);
|
const target = __owl__.vnode || document.createElement(vnode.sel!);
|
||||||
__owl__.vnode = patch(target, vnode);
|
__owl__.vnode = patch(target, vnode);
|
||||||
__owl__.currentFiber = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ export class Fiber {
|
|||||||
const fiber = patchQueue[i];
|
const fiber = patchQueue[i];
|
||||||
component = fiber.component;
|
component = fiber.component;
|
||||||
component.__patch(fiber.vnode);
|
component.__patch(fiber.vnode);
|
||||||
|
component.__owl__.currentFiber = null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
for (let i = patchLen - 1; i >= 0; i--) {
|
for (let i = patchLen - 1; i >= 0; i--) {
|
||||||
|
|||||||
@@ -4889,6 +4889,37 @@ describe("unmounting and remounting", () => {
|
|||||||
await widget.mount(fixture);
|
await widget.mount(fixture);
|
||||||
expect(fixture.innerHTML).toBe("<div>3</div>");
|
expect(fixture.innerHTML).toBe("<div>3</div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("sub component is still active after being unmounted and remounted", async () => {
|
||||||
|
class Child extends Component<any, any> {
|
||||||
|
static template = xml`
|
||||||
|
<p t-on-click="state.value++">
|
||||||
|
<t t-esc="state.value"/>
|
||||||
|
</p>`;
|
||||||
|
|
||||||
|
state = useState({ value: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component<any, any> {
|
||||||
|
static components = { Child };
|
||||||
|
static template = xml`<div><Child/></div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const w = new Parent();
|
||||||
|
await w.mount(fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("<div><p>1</p></div>");
|
||||||
|
|
||||||
|
fixture.querySelector("p")!.click();
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("<div><p>2</p></div>");
|
||||||
|
w.unmount();
|
||||||
|
await nextTick();
|
||||||
|
await w.mount(fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("<div><p>2</p></div>");
|
||||||
|
fixture.querySelector("p")!.click();
|
||||||
|
await nextTick();
|
||||||
|
expect(fixture.innerHTML).toBe("<div><p>3</p></div>");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("dynamic root nodes", () => {
|
describe("dynamic root nodes", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user