From 16bd9b7f5e30171707edb0c2a6f1352dea4bdcd0 Mon Sep 17 00:00:00 2001 From: Jan Henrik Overland Date: Mon, 9 Mar 2020 18:08:19 +0100 Subject: [PATCH 1/6] fix: memoize items --- package.json | 1 + src/components/ItemGrid/ItemGrid.js | 87 ++++++++++++++++++----------- yarn.lock | 5 ++ 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 403c0b03a..611747016 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "d2-utilizr": "^0.2.16", "i18next": "^15.0.6", "lodash": "^4.17.11", + "memoize-one": "^5.1.1", "moment": "^2.24.0", "react": "^16.8.4", "react-dom": "^16.8.4", diff --git a/src/components/ItemGrid/ItemGrid.js b/src/components/ItemGrid/ItemGrid.js index 7eab80a1f..524887026 100644 --- a/src/components/ItemGrid/ItemGrid.js +++ b/src/components/ItemGrid/ItemGrid.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; +import memoize from 'lodash/memoize'; import i18n from '@dhis2/d2-i18n'; import ReactGridLayout from 'react-grid-layout'; import { CircularLoader, ScreenCover } from '@dhis2/ui-core'; @@ -49,6 +50,15 @@ export class ItemGrid extends Component { expandedItems: {}, }; + constructor(props) { + super(props); + + this.getMemoizedItem = memoize(this.getItem); + this.getMemoizedItems = memoize(this.getItems); + this.getMemoizedItemComponent = memoize(this.getItemComponent); + this.getMemoizedItemComponents = memoize(this.getItemComponents); + } + onToggleItemExpanded = clickedId => { const isExpanded = typeof this.state.expandedItems[clickedId] === 'boolean' @@ -91,6 +101,47 @@ export class ItemGrid extends Component { onRemoveItemWrapper = id => () => this.onRemoveItem(id); + getItem = dashboardItem => { + const expandedItem = this.state.expandedItems[dashboardItem.id]; + const hProp = { h: dashboardItem.h }; + + if (expandedItem && expandedItem === true) { + hProp.h = dashboardItem.h + EXPANDED_HEIGHT; + } + + return Object.assign({}, dashboardItem, hProp, { + i: dashboardItem.id, + minH: ITEM_MIN_HEIGHT, + randomNumber: Math.random(), + }); + }; + + getItems = dashboardItems => + dashboardItems.map(item => this.getMemoizedItem(item)); + + getItemComponent = item => { + const itemClassNames = [ + item.type, + this.props.edit ? 'edit' : 'view', + ].join(' '); + + return ( + + + + ); + }; + + getItemComponents = items => + items.map(item => this.getMemoizedItemComponent(item)); + render() { const { edit, isLoading, dashboardItems } = this.props; @@ -102,19 +153,7 @@ export class ItemGrid extends Component { ); } - const items = dashboardItems.map(item => { - const expandedItem = this.state.expandedItems[item.id]; - const hProp = { h: item.h }; - - if (expandedItem && expandedItem === true) { - hProp.h = item.h + EXPANDED_HEIGHT; - } - - return Object.assign({}, item, hProp, { - i: item.id, - minH: ITEM_MIN_HEIGHT, - }); - }); + const items = this.getMemoizedItems(dashboardItems); return (
@@ -137,27 +176,7 @@ export class ItemGrid extends Component { isResizable={edit} draggableCancel="input,textarea" > - {items.map(item => { - const itemClassNames = [ - item.type, - edit ? 'edit' : 'view', - ].join(' '); - - return ( - - - - ); - })} + {this.getMemoizedItemComponents(items)}
); diff --git a/yarn.lock b/yarn.lock index 6c292c128..2e3b4e0be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8639,6 +8639,11 @@ memoize-one@^5.0.0, memoize-one@^5.0.1: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.4.tgz#005928aced5c43d890a4dfab18ca908b0ec92cbc" integrity sha512-P0z5IeAH6qHHGkJIXWw0xC2HNEgkx/9uWWBQw64FJj3/ol14VYdfVGWWr0fXfjhhv3TKVIqUq65os6O4GUNksA== +memoize-one@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" + integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA== + memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" From 6051a5723a7320f1a93372854f183c712150201b Mon Sep 17 00:00:00 2001 From: Jan Henrik Overland Date: Mon, 9 Mar 2020 20:19:01 +0100 Subject: [PATCH 2/6] fix: only reproduce changed items --- src/reducers/editDashboard.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/reducers/editDashboard.js b/src/reducers/editDashboard.js index 966c58913..942b4326f 100644 --- a/src/reducers/editDashboard.js +++ b/src/reducers/editDashboard.js @@ -66,16 +66,32 @@ export default (state = DEFAULT_STATE_EDIT_DASHBOARD, action) => { } case RECEIVED_DASHBOARD_LAYOUT: { const stateItems = orArray(state.dashboardItems); + let layoutHasChanged = false; const newStateItems = action.value.map(({ x, y, w, h, i }) => { const stateItem = stateItems.find(si => si.id === i); - return Object.assign({}, stateItem, { w, h, x, y }); + if ( + !( + stateItem.x === x && + stateItem.y === y && + stateItem.w === w && + stateItem.h === h + ) + ) { + layoutHasChanged = true; + return Object.assign({}, stateItem, { w, h, x, y }); + } + + return stateItem; }); - return update(state, { - dashboardItems: { $set: newStateItems }, - }); + return layoutHasChanged + ? { + ...state, + dashboardItems: newStateItems, + } + : state; } case UPDATE_DASHBOARD_ITEM: { const dashboardItem = action.value; From 5846456313ffe5265a19f7ed3692cc309b466cfb Mon Sep 17 00:00:00 2001 From: Jan Henrik Overland Date: Mon, 9 Mar 2020 20:20:53 +0100 Subject: [PATCH 3/6] fix: remove memoize-one --- package.json | 1 - yarn.lock | 5 ----- 2 files changed, 6 deletions(-) diff --git a/package.json b/package.json index 611747016..403c0b03a 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "d2-utilizr": "^0.2.16", "i18next": "^15.0.6", "lodash": "^4.17.11", - "memoize-one": "^5.1.1", "moment": "^2.24.0", "react": "^16.8.4", "react-dom": "^16.8.4", diff --git a/yarn.lock b/yarn.lock index 2e3b4e0be..6c292c128 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8639,11 +8639,6 @@ memoize-one@^5.0.0, memoize-one@^5.0.1: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.4.tgz#005928aced5c43d890a4dfab18ca908b0ec92cbc" integrity sha512-P0z5IeAH6qHHGkJIXWw0xC2HNEgkx/9uWWBQw64FJj3/ol14VYdfVGWWr0fXfjhhv3TKVIqUq65os6O4GUNksA== -memoize-one@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" - integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA== - memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" From 0d25799bd90dd007791872b1a10122086029116b Mon Sep 17 00:00:00 2001 From: Jan Henrik Overland Date: Mon, 9 Mar 2020 20:26:38 +0100 Subject: [PATCH 4/6] fix: only memo in edit mode (view mode using local state: expanded item) --- src/components/ItemGrid/ItemGrid.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/ItemGrid/ItemGrid.js b/src/components/ItemGrid/ItemGrid.js index 524887026..dfe716bea 100644 --- a/src/components/ItemGrid/ItemGrid.js +++ b/src/components/ItemGrid/ItemGrid.js @@ -153,7 +153,9 @@ export class ItemGrid extends Component { ); } - const items = this.getMemoizedItems(dashboardItems); + const items = edit + ? this.getMemoizedItems(dashboardItems) + : dashboardItems.map(this.getItem); return (
From 9c9ea48eecd65ca4cde126c5b92607d428cf9a4e Mon Sep 17 00:00:00 2001 From: Jan Henrik Overland Date: Mon, 9 Mar 2020 20:28:37 +0100 Subject: [PATCH 5/6] fix: use lodash memoize --- src/components/Item/VisualizationItem/Item.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index 10085e830..05002d476 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -1,6 +1,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; +import memoize from 'lodash/memoize'; import { withStyles } from '@material-ui/core/styles'; import VisualizationPlugin from '@dhis2/data-visualizer-plugin'; @@ -28,7 +29,6 @@ import { import { colors } from '@dhis2/ui-core'; import { getVisualizationConfig } from './plugin'; import LoadingMask from './LoadingMask'; -import memoizeOne from '../../../modules/memoizeOne'; const HEADER_HEIGHT = 45; @@ -77,11 +77,9 @@ export class Item extends Component { this.contentRef = React.createRef(); - this.memoizedApplyFilters = memoizeOne(this.applyFilters); + this.memoizedApplyFilters = memoize(this.applyFilters); - this.memoizedGetVisualizationConfig = memoizeOne( - getVisualizationConfig - ); + this.memoizedGetVisualizationConfig = memoize(getVisualizationConfig); } async componentDidMount() { @@ -148,7 +146,7 @@ export class Item extends Component { }; }; - getUniqueKey = memoizeOne(() => uniqueId()); + getUniqueKey = memoize(() => uniqueId()); pluginCredentials = null; From 436574c93a22ba4f62e8ba89076f78c443d17606 Mon Sep 17 00:00:00 2001 From: Jan Henrik Overland Date: Tue, 10 Mar 2020 11:29:58 +0100 Subject: [PATCH 6/6] fix: use memoizeOne for filters, remove unnecessary memoization of items --- src/components/Item/VisualizationItem/Item.js | 13 +++++++------ src/components/ItemGrid/ItemGrid.js | 10 +++------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index 05002d476..1b4f07d99 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -1,12 +1,10 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import memoize from 'lodash/memoize'; import { withStyles } from '@material-ui/core/styles'; +import uniqueId from 'lodash/uniqueId'; import VisualizationPlugin from '@dhis2/data-visualizer-plugin'; - import i18n from '@dhis2/d2-i18n'; -import uniqueId from 'lodash/uniqueId'; import DefaultPlugin from './DefaultPlugin'; import ItemHeader from '../ItemHeader'; @@ -25,6 +23,7 @@ import { CHART, REPORT_TABLE, } from '../../../modules/itemTypes'; +import memoizeOne from '../../../modules/memoizeOne'; import { colors } from '@dhis2/ui-core'; import { getVisualizationConfig } from './plugin'; @@ -77,9 +76,11 @@ export class Item extends Component { this.contentRef = React.createRef(); - this.memoizedApplyFilters = memoize(this.applyFilters); + this.memoizedApplyFilters = memoizeOne(this.applyFilters); - this.memoizedGetVisualizationConfig = memoize(getVisualizationConfig); + this.memoizedGetVisualizationConfig = memoizeOne( + getVisualizationConfig + ); } async componentDidMount() { @@ -146,7 +147,7 @@ export class Item extends Component { }; }; - getUniqueKey = memoize(() => uniqueId()); + getUniqueKey = memoizeOne(() => uniqueId()); pluginCredentials = null; diff --git a/src/components/ItemGrid/ItemGrid.js b/src/components/ItemGrid/ItemGrid.js index dfe716bea..df9eb7a7a 100644 --- a/src/components/ItemGrid/ItemGrid.js +++ b/src/components/ItemGrid/ItemGrid.js @@ -54,9 +54,6 @@ export class ItemGrid extends Component { super(props); this.getMemoizedItem = memoize(this.getItem); - this.getMemoizedItems = memoize(this.getItems); - this.getMemoizedItemComponent = memoize(this.getItemComponent); - this.getMemoizedItemComponents = memoize(this.getItemComponents); } onToggleItemExpanded = clickedId => { @@ -139,8 +136,7 @@ export class ItemGrid extends Component { ); }; - getItemComponents = items => - items.map(item => this.getMemoizedItemComponent(item)); + getItemComponents = items => items.map(item => this.getItemComponent(item)); render() { const { edit, isLoading, dashboardItems } = this.props; @@ -154,7 +150,7 @@ export class ItemGrid extends Component { } const items = edit - ? this.getMemoizedItems(dashboardItems) + ? this.getItems(dashboardItems) : dashboardItems.map(this.getItem); return ( @@ -178,7 +174,7 @@ export class ItemGrid extends Component { isResizable={edit} draggableCancel="input,textarea" > - {this.getMemoizedItemComponents(items)} + {this.getItemComponents(items)}
);