mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] implement .alike suffix on props
It is common in Owl components to have anonymous function as props. However, since each rendering create a different (but equivalent) closure, Owl will consider the props different, so will update the child component, but this is (often) not necessary. This commit will help reduce the problem by introducing a new `.alike` prop suffix, that will let Owl know that each version of that specific prop should be considered the same, so, will be ignored by the props comparison code. closes #1360
This commit is contained in:
committed by
Sam Degueldre
parent
aadc9eafa3
commit
a51b286671
@@ -1132,12 +1132,15 @@ export class CodeGenerator {
|
||||
value = this.captureExpression(value);
|
||||
if (name.includes(".")) {
|
||||
let [_name, suffix] = name.split(".");
|
||||
if (suffix === "bind") {
|
||||
this.helpers.add("bind");
|
||||
name = _name;
|
||||
value = `bind(this, ${value || undefined})`;
|
||||
} else {
|
||||
throw new OwlError("Invalid prop suffix");
|
||||
name = _name;
|
||||
switch (suffix) {
|
||||
case "bind":
|
||||
value = `${value}.bind(this)`;
|
||||
break;
|
||||
case "alike":
|
||||
break;
|
||||
default:
|
||||
throw new OwlError("Invalid prop suffix");
|
||||
}
|
||||
}
|
||||
name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
|
||||
@@ -1237,13 +1240,18 @@ export class CodeGenerator {
|
||||
keyArg = `${ctx.tKeyExpr} + ${keyArg}`;
|
||||
}
|
||||
let id = generateId("comp");
|
||||
const propList: string[] = [];
|
||||
for (let p in ast.props || {}) {
|
||||
let [name, suffix] = p.split(".");
|
||||
if (!suffix) {
|
||||
propList.push(`"${name}"`);
|
||||
}
|
||||
}
|
||||
this.staticDefs.push({
|
||||
id,
|
||||
expr: `app.createComponent(${
|
||||
ast.isDynamic ? null : expr
|
||||
}, ${!ast.isDynamic}, ${!!ast.slots}, ${!!ast.dynamicProps}, ${
|
||||
!ast.props && !ast.dynamicProps
|
||||
})`,
|
||||
}, ${!ast.isDynamic}, ${!!ast.slots}, ${!!ast.dynamicProps}, [${propList}])`,
|
||||
});
|
||||
|
||||
if (ast.isDynamic) {
|
||||
|
||||
+25
-12
@@ -139,22 +139,35 @@ export class App<
|
||||
isStatic: boolean,
|
||||
hasSlotsProp: boolean,
|
||||
hasDynamicPropList: boolean,
|
||||
hasNoProp: boolean
|
||||
propList: string[]
|
||||
) {
|
||||
const isDynamic = !isStatic;
|
||||
function _arePropsDifferent(props1: Props, props2: Props): boolean {
|
||||
for (let k in props1) {
|
||||
if (props1[k] !== props2[k]) {
|
||||
return true;
|
||||
let arePropsDifferent: (p1: Object, p2: Object) => boolean;
|
||||
const hasNoProp = propList.length === 0;
|
||||
if (hasSlotsProp) {
|
||||
arePropsDifferent = (_1, _2) => true;
|
||||
} else if (hasDynamicPropList) {
|
||||
arePropsDifferent = function (props1: Props, props2: Props) {
|
||||
for (let k in props1) {
|
||||
if (props1[k] !== props2[k]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasDynamicPropList && Object.keys(props1).length !== Object.keys(props2).length;
|
||||
return Object.keys(props1).length !== Object.keys(props2).length;
|
||||
};
|
||||
} else if (hasNoProp) {
|
||||
arePropsDifferent = (_1: any, _2: any) => false;
|
||||
} else {
|
||||
arePropsDifferent = function (props1: Props, props2: Props) {
|
||||
for (let p of propList) {
|
||||
if (props1[p] !== props2[p]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
const arePropsDifferent = hasSlotsProp
|
||||
? (_1: any, _2: any) => true
|
||||
: hasNoProp
|
||||
? (_1: any, _2: any) => false
|
||||
: _arePropsDifferent;
|
||||
|
||||
const updateAndRender = ComponentNode.prototype.updateAndRender;
|
||||
const initiateRender = ComponentNode.prototype.initiateRender;
|
||||
|
||||
|
||||
@@ -167,24 +167,6 @@ export function safeOutput(value: any, defaultValue?: any): ReturnType<typeof to
|
||||
return toggler(safeKey, block);
|
||||
}
|
||||
|
||||
let boundFunctions = new WeakMap();
|
||||
const WeakMapGet = WeakMap.prototype.get;
|
||||
const WeakMapSet = WeakMap.prototype.set;
|
||||
|
||||
function bind(component: any, fn: Function): Function {
|
||||
let boundFnMap = WeakMapGet.call(boundFunctions, component);
|
||||
if (!boundFnMap) {
|
||||
boundFnMap = new WeakMap();
|
||||
WeakMapSet.call(boundFunctions, component, boundFnMap);
|
||||
}
|
||||
let boundFn = WeakMapGet.call(boundFnMap, fn);
|
||||
if (!boundFn) {
|
||||
boundFn = fn.bind(component);
|
||||
WeakMapSet.call(boundFnMap, fn, boundFn);
|
||||
}
|
||||
return boundFn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the component props (or next props) against the (static) props
|
||||
* description. This is potentially an expensive operation: it may needs to
|
||||
@@ -260,7 +242,6 @@ export const helpers = {
|
||||
validateProps,
|
||||
LazyValue,
|
||||
safeOutput,
|
||||
bind,
|
||||
createCatcher,
|
||||
markRaw,
|
||||
OwlError,
|
||||
|
||||
Reference in New Issue
Block a user