diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index 10085e830..1b4f07d99 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -2,10 +2,9 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; 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'; @@ -24,11 +23,11 @@ import { CHART, REPORT_TABLE, } from '../../../modules/itemTypes'; +import memoizeOne from '../../../modules/memoizeOne'; import { colors } from '@dhis2/ui-core'; import { getVisualizationConfig } from './plugin'; import LoadingMask from './LoadingMask'; -import memoizeOne from '../../../modules/memoizeOne'; const HEADER_HEIGHT = 45; diff --git a/src/components/ItemGrid/ItemGrid.js b/src/components/ItemGrid/ItemGrid.js index 7eab80a1f..df9eb7a7a 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,12 @@ export class ItemGrid extends Component { expandedItems: {}, }; + constructor(props) { + super(props); + + this.getMemoizedItem = memoize(this.getItem); + } + onToggleItemExpanded = clickedId => { const isExpanded = typeof this.state.expandedItems[clickedId] === 'boolean' @@ -91,6 +98,46 @@ 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.getItemComponent(item)); + render() { const { edit, isLoading, dashboardItems } = this.props; @@ -102,19 +149,9 @@ 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 = edit + ? this.getItems(dashboardItems) + : dashboardItems.map(this.getItem); return (
@@ -137,27 +174,7 @@ export class ItemGrid extends Component { isResizable={edit} draggableCancel="input,textarea" > - {items.map(item => { - const itemClassNames = [ - item.type, - edit ? 'edit' : 'view', - ].join(' '); - - return ( - - - - ); - })} + {this.getItemComponents(items)}
); 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;