[IMP] web: add shouldUpdate=false to some components

We add in this commit a "decorator" to make components that do not
rerender when their parent is updating them. This makes sense for some
main components that knows before hand that they do not depend on a
props change.

This commit is mostly an optimization to avoid useless work by owl, but
it also has some interesting properties: before this commit, each
dialogs would be rerendered whenever a new dialog is added. This could
be an issue if the rendering of one of them causes an error, which needs
in turn to add a dialog, ...

closes odoo-dev/odoo#970

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Géry Debongnie
2021-06-18 21:31:34 +02:00
committed by Aaron Bohy
parent ea0a718fb4
commit 97c88e8c06
6 changed files with 67 additions and 1 deletions
@@ -7,6 +7,9 @@ class ErrorHandler extends Component {
this.props.callback();
throw error;
}
shouldUpdate() {
return false;
}
}
ErrorHandler.template = tags.xml`<t t-component="props.dialog.class" t-props="props.dialog.props" />`;
@@ -9,6 +9,10 @@ export class Notification extends Component {
}
}
shouldUpdate() {
return false;
}
get className() {
let className;
switch (this.props.type) {
@@ -19,6 +19,11 @@ class PopoverController extends Component {
willUnmount() {
this.targetObserver.disconnect();
}
shouldUpdate() {
return false;
}
get popoverProps() {
return {
target: this.target,
@@ -0,0 +1,15 @@
/** @odoo-module **/
const { Component, tags } = owl;
export function makeNonUpdatableComponent(Comp) {
class NoUpdate extends Component {
shouldUpdate() {
return false;
}
}
NoUpdate.template = tags.xml`<t t-component="Comp" t-props="props"/>`;
NoUpdate.components = { Comp };
return NoUpdate;
}
+6 -1
View File
@@ -6,6 +6,7 @@ import { useBus } from "../core/bus_hook";
import { ActionContainer } from "./actions/action_container";
import { NavBar } from "./navbar/navbar";
import { useEffect } from "@web/core/effect_hook";
import { makeNonUpdatableComponent } from "../core/utils/components";
const { Component, hooks } = owl;
const { useExternalListener } = hooks;
@@ -19,7 +20,11 @@ export class WebClient extends Component {
this.router = useService("router");
this.user = useService("user");
useService("legacy_service_provider");
this.Components = mainComponentRegistry.getEntries();
this.Components = mainComponentRegistry.getEntries().map(([name, elem]) => {
const { Component, props } = elem;
const NonUpdatableComp = makeNonUpdatableComponent(Component);
return [name, { Component: NonUpdatableComp, props }];
});
this.title.setParts({ zopenerp: "Odoo" }); // zopenerp is easy to grep
useBus(this.env.bus, "ROUTE_CHANGE", this.loadRouterState);
useBus(this.env.bus, "ACTION_MANAGER:UI-UPDATED", (mode) => {
@@ -0,0 +1,34 @@
/** @odoo-module **/
import { makeNonUpdatableComponent } from "@web/core/utils/components";
import { makeTestEnv } from "../../helpers/mock_env";
import { getFixture } from "../../helpers/utils";
const { Component, mount } = owl;
QUnit.module("utils", () => {
QUnit.module("components");
QUnit.test("makeNonUpdatableComponent", async function (assert) {
class Child extends Component {
mounted() {
assert.step("mounted");
}
willUpdateProps() {
assert.step("willupdateprops");
}
}
Child.template = owl.tags.xml`<div>hey</div>`;
class Parent extends Component {}
Parent.template = owl.tags.xml`<div><Child1/><Child2/></div>`;
Parent.components = { Child1: Child, Child2: makeNonUpdatableComponent(Child) };
const target = getFixture();
const parent = await mount(Parent, { env: makeTestEnv(), target });
assert.verifySteps(["mounted", "mounted"]);
await parent.render();
assert.verifySteps(["willupdateprops"]);
parent.destroy();
});
});