summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/bugfix
diff options
context:
space:
mode:
authorSébastien Theys <seb@odoo.com>2021-01-21 17:43:49 +0000
committerSébastien Theys <seb@odoo.com>2021-01-21 17:43:49 +0000
commit7f9af5747c7b650b6cf4ab894bdd0b113e77a78b (patch)
tree5152dca1d14355e7c7465b41fcbe9c80770e98a6 /addons/mail/static/src/bugfix
parent47bfdf0592a5dd93870ca1a9da326351d70087bb (diff)
[FIX] mail, *: significantly reduce number of useless renders
* = hr_holidays, im_livechat, website_livechat A huge amount of components where rendered for no reason, notably when typing a new message (at every key press), which significantly slowed down the interface. There were 2 causes to this number of renders: - OWL rendering all children automatically, even if their props didn't change, unless `shouldUpdate` is overridden, which is now done. - `useStore` selectors being way too generous in what they observed task-2399731 closes odoo/odoo#62703 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
Diffstat (limited to 'addons/mail/static/src/bugfix')
-rw-r--r--addons/mail/static/src/bugfix/bugfix.js74
1 files changed, 74 insertions, 0 deletions
diff --git a/addons/mail/static/src/bugfix/bugfix.js b/addons/mail/static/src/bugfix/bugfix.js
index 162bf606db5..4a8bb890bff 100644
--- a/addons/mail/static/src/bugfix/bugfix.js
+++ b/addons/mail/static/src/bugfix/bugfix.js
@@ -115,3 +115,77 @@ function useUpdate({ func, priority }) {
return useUpdate;
});
+
+// Should be moved to its own file in master.
+odoo.define('mail/static/src/component_hooks/use_should_update_based_on_props/use_should_update_based_on_props.js', function (require) {
+'use strict';
+
+const { Component } = owl;
+
+/**
+ * Compares `a` and `b` up to the given `compareDepth`.
+ *
+ * @param {any} a
+ * @param {any} b
+ * @param {Object|integer} compareDepth
+ * @returns {boolean}
+ */
+function isEqual(a, b, compareDepth) {
+ const keys = Object.keys(a);
+ if (Object.keys(b).length !== keys.length) {
+ return false;
+ }
+ for (const key of keys) {
+ // the depth can be given either as a number (for all keys) or as
+ // an object (for each key)
+ let depth;
+ if (typeof compareDepth === 'number') {
+ depth = compareDepth;
+ } else {
+ depth = compareDepth[key] || 0;
+ }
+ if (depth === 0 && a[key] !== b[key]) {
+ return false;
+ }
+ if (depth !== 0) {
+ let nextDepth;
+ if (typeof depth === 'number') {
+ nextDepth = depth - 1;
+ } else {
+ nextDepth = depth;
+ }
+ if (!isEqual(a[key], b[key], nextDepth)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * This hook overrides the `shouldUpdate` method to ensure the component is only
+ * updated if its props actually changed. This is especially useful to use on
+ * components for which an extra render costs proportionally a lot more than
+ * comparing props.
+ *
+ * @param {Object} [param0={}]
+ * @param {Object} [param0.compareDepth={}] allows to specify the comparison
+ * depth to use for each prop. Default is shallow compare (depth = 0).
+ */
+function useShouldUpdateBasedOnProps({ compareDepth = {} } = {}) {
+ const component = Component.current;
+ component.shouldUpdate = nextProps => {
+ const allNewProps = Object.assign({}, nextProps);
+ const defaultProps = component.constructor.defaultProps;
+ for (const key in defaultProps) {
+ if (allNewProps[key] === undefined) {
+ allNewProps[key] = defaultProps[key];
+ }
+ }
+ return !isEqual(component.props, allNewProps, compareDepth);
+ };
+}
+
+return useShouldUpdateBasedOnProps;
+
+});