mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] component: use reactivity to allow shallow renderings
With this commit, component only render child components if they have different props (shallow equality). Otherwise, we trust the reactivity system to make sure that all impacted components are updated
This commit is contained in:
committed by
Samuel Degueldre
parent
592d9a458e
commit
1ae9d514b9
@@ -39,6 +39,8 @@ Scheduler.prototype.addFiber = function (fiber: Fiber) {
|
||||
|
||||
afterEach(() => {
|
||||
if (lastScheduler && lastScheduler.tasks.size > 0) {
|
||||
// we still clear the scheduler to prevent additional noise
|
||||
lastScheduler.tasks.clear();
|
||||
throw new Error("we got a memory leak...");
|
||||
}
|
||||
});
|
||||
@@ -131,6 +133,58 @@ test("destroying/recreating a subwidget with different props (if start is not ov
|
||||
]).toBeLogged();
|
||||
});
|
||||
|
||||
test("destroying/recreating a subcomponent, other scenario", async () => {
|
||||
let flag = false;
|
||||
|
||||
class Child extends Component {
|
||||
static template = xml`child`;
|
||||
setup() {
|
||||
if (!flag) {
|
||||
flag = true;
|
||||
parent.render(true);
|
||||
}
|
||||
useLogLifecycle();
|
||||
}
|
||||
}
|
||||
|
||||
class Parent extends Component {
|
||||
static template = xml`parent<Child t-if="state.hasChild"/>`;
|
||||
static components = { Child };
|
||||
state = useState({ hasChild: false });
|
||||
setup() {
|
||||
useLogLifecycle();
|
||||
}
|
||||
}
|
||||
|
||||
const parent = await mount(Parent, fixture);
|
||||
|
||||
expect([
|
||||
"Parent:setup",
|
||||
"Parent:willStart",
|
||||
"Parent:willRender",
|
||||
"Parent:rendered",
|
||||
"Parent:mounted",
|
||||
]).toBeLogged();
|
||||
expect(fixture.innerHTML).toBe("parent");
|
||||
|
||||
parent.state.hasChild = true;
|
||||
|
||||
await nextTick();
|
||||
expect([
|
||||
"Parent:willRender",
|
||||
"Child:setup",
|
||||
"Child:willStart",
|
||||
"Parent:rendered",
|
||||
"Child:willRender",
|
||||
"Child:rendered",
|
||||
"Parent:willPatch",
|
||||
"Child:mounted",
|
||||
"Parent:patched",
|
||||
]).toBeLogged();
|
||||
|
||||
expect(fixture.innerHTML).toBe("parentchild");
|
||||
});
|
||||
|
||||
test("creating two async components, scenario 1", async () => {
|
||||
let defA = makeDeferred();
|
||||
let defB = makeDeferred();
|
||||
@@ -521,7 +575,7 @@ test("properly behave when destroyed/unmounted while rendering ", async () => {
|
||||
}
|
||||
|
||||
class Child extends Component {
|
||||
static template = xml`<div><SubChild /></div>`;
|
||||
static template = xml`<div><SubChild val="props.val"/></div>`;
|
||||
static components = { SubChild };
|
||||
setup() {
|
||||
useLogLifecycle();
|
||||
@@ -1907,18 +1961,13 @@ test("concurrent renderings scenario 13", async () => {
|
||||
await nextTick(); // wait for this change to be applied
|
||||
expect([
|
||||
"Parent:willRender",
|
||||
"Child:willUpdateProps",
|
||||
"Child:setup",
|
||||
"Child:willStart",
|
||||
"Parent:rendered",
|
||||
"Child:willRender",
|
||||
"Child:rendered",
|
||||
"Child:willRender",
|
||||
"Child:rendered",
|
||||
"Parent:willPatch",
|
||||
"Child:willPatch",
|
||||
"Child:mounted",
|
||||
"Child:patched",
|
||||
"Parent:patched",
|
||||
"Child:willRender",
|
||||
"Child:rendered",
|
||||
@@ -2472,9 +2521,9 @@ test("two renderings initiated between willPatch and patched", async () => {
|
||||
useLogLifecycle();
|
||||
onMounted(() => {
|
||||
this.mounted = "Mounted";
|
||||
parent.render();
|
||||
parent.render(true);
|
||||
});
|
||||
onWillUnmount(() => parent.render());
|
||||
onWillUnmount(() => parent.render(true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2507,15 +2556,11 @@ test("two renderings initiated between willPatch and patched", async () => {
|
||||
"Parent:rendered",
|
||||
]).toBeLogged();
|
||||
|
||||
await nextMicroTick();
|
||||
expect(["Panel:willRender", "Panel:rendered"]).toBeLogged();
|
||||
|
||||
await nextTick();
|
||||
expect([
|
||||
"Panel:willRender",
|
||||
"Panel:rendered",
|
||||
"Parent:willPatch",
|
||||
"Panel:willPatch",
|
||||
"Panel:patched",
|
||||
"Parent:patched",
|
||||
]).toBeLogged();
|
||||
expect(["Parent:willPatch", "Panel:willPatch", "Panel:patched", "Parent:patched"]).toBeLogged();
|
||||
expect(fixture.innerHTML).toBe("<div><abc>Panel1Mounted</abc></div>");
|
||||
|
||||
parent.state.panel = "Panel2";
|
||||
@@ -2753,12 +2798,20 @@ test("delay willUpdateProps with rendering grandchild", async () => {
|
||||
static template = xml`<Parent state="state"/>`;
|
||||
static components = { Parent };
|
||||
state = { value: 0 };
|
||||
setup() {
|
||||
useLogLifecycle();
|
||||
}
|
||||
}
|
||||
|
||||
const parent = await mount(GrandParent, fixture);
|
||||
expect(fixture.innerHTML).toBe("0_0<div></div>");
|
||||
expect([
|
||||
"GrandParent:setup",
|
||||
"GrandParent:willStart",
|
||||
"GrandParent:willRender",
|
||||
"Parent:setup",
|
||||
"Parent:willStart",
|
||||
"GrandParent:rendered",
|
||||
"Parent:willRender",
|
||||
"DelayedChild:setup",
|
||||
"DelayedChild:willStart",
|
||||
@@ -2772,20 +2825,23 @@ test("delay willUpdateProps with rendering grandchild", async () => {
|
||||
"ReactiveChild:mounted",
|
||||
"DelayedChild:mounted",
|
||||
"Parent:mounted",
|
||||
"GrandParent:mounted",
|
||||
]).toBeLogged();
|
||||
|
||||
promise = makeDeferred();
|
||||
const prom1 = promise;
|
||||
parent.state.value = 1;
|
||||
child.render(); // trigger a root rendering first
|
||||
parent.render();
|
||||
parent.render(true);
|
||||
reactiveChild.render();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("0_0<div></div>");
|
||||
expect([
|
||||
"DelayedChild:willRender",
|
||||
"DelayedChild:rendered",
|
||||
"GrandParent:willRender",
|
||||
"Parent:willUpdateProps",
|
||||
"GrandParent:rendered",
|
||||
"ReactiveChild:willRender",
|
||||
"ReactiveChild:rendered",
|
||||
"Parent:willRender",
|
||||
@@ -2800,12 +2856,14 @@ test("delay willUpdateProps with rendering grandchild", async () => {
|
||||
const prom2 = promise;
|
||||
child.render(); // trigger a root rendering first
|
||||
parent.state.value = 2;
|
||||
parent.render();
|
||||
parent.render(true);
|
||||
reactiveChild.render();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("0_0<div></div>");
|
||||
expect([
|
||||
"GrandParent:willRender",
|
||||
"Parent:willUpdateProps",
|
||||
"GrandParent:rendered",
|
||||
"ReactiveChild:willRender",
|
||||
"ReactiveChild:rendered",
|
||||
"Parent:willRender",
|
||||
@@ -2822,12 +2880,14 @@ test("delay willUpdateProps with rendering grandchild", async () => {
|
||||
expect([
|
||||
"DelayedChild:willRender",
|
||||
"DelayedChild:rendered",
|
||||
"GrandParent:willPatch",
|
||||
"Parent:willPatch",
|
||||
"ReactiveChild:willPatch",
|
||||
"DelayedChild:willPatch",
|
||||
"DelayedChild:patched",
|
||||
"ReactiveChild:patched",
|
||||
"Parent:patched",
|
||||
"GrandParent:patched",
|
||||
]).toBeLogged();
|
||||
|
||||
prom1.resolve();
|
||||
|
||||
Reference in New Issue
Block a user