Skip to content

Commit a2e3f1c

Browse files
author
Chris Thomas
committed
Cache Child Props
Cache the child props to prevent React from re-rendering unnessesarily. The biggest culprits were the default accessors. The defaults for each attribute are now computed once, and re-used when required.
1 parent cce5980 commit a2e3f1c

File tree

3 files changed

+67
-20
lines changed

3 files changed

+67
-20
lines changed

.eslintrc

+8-6
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
"**/dist/",
2020
"**/es/"
2121
],
22-
"settings":{
23-
"react":{
22+
"settings": {
23+
"react": {
2424
"version": "detect"
2525
}
2626
},
@@ -31,12 +31,14 @@
3131
},
3232
"rules": {
3333
"consistent-return": 0,
34-
"max-len": [1, 110, 4],
35-
"max-params": ["error", 6],
34+
"max-params": [
35+
"error",
36+
6
37+
],
3638
"object-curly-spacing": 0,
3739
"babel/object-curly-spacing": 2,
38-
"jest/require-top-level-describe":"error",
40+
"jest/require-top-level-describe": "error",
3941
"react/prop-types": "off",
4042
"prettier/prettier": "warn"
4143
}
42-
}
44+
}

packages/react-vis/src/plot/xy-plot.js

+31-8
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020

2121
import React from 'react';
2222
import PropTypes from 'prop-types';
23-
import equal from 'deep-equal';
23+
// import equal from 'deep-equal';
24+
import equal from 'lodash/isEqual';
2425

2526
import {getCombinedClassName} from 'utils/styling-utils';
2627

@@ -188,6 +189,22 @@ class XYPlot extends React.Component {
188189
}
189190
};
190191

192+
_childPropCache = Object.create(null);
193+
194+
/**
195+
* Memoizes the props of the child.
196+
* This is keyed off of the childs 'key' property or defaults to its index.
197+
* @param {number} index The index of the child
198+
* @param {object} newValues The childs props
199+
*/
200+
_getChildProps(index, newValues) {
201+
const key = newValues.key || `@@series-${index}`;
202+
const cached = this._childPropCache[key];
203+
if (!equal(cached, newValues)) {
204+
this._childPropCache[key] = {...newValues};
205+
}
206+
return this._childPropCache[key];
207+
}
191208
/**
192209
* Prepare the child components (including series) for rendering.
193210
* @returns {Array} Array of child components.
@@ -201,6 +218,7 @@ class XYPlot extends React.Component {
201218
const children = React.Children.toArray(this.props.children);
202219
const seriesProps = getSeriesPropsFromChildren(children);
203220
const XYPlotValues = getXYPlotValues(props, children);
221+
204222
return children.map((child, index) => {
205223
let dataProps = null;
206224
if (seriesProps[index]) {
@@ -209,21 +227,26 @@ class XYPlot extends React.Component {
209227
const {seriesIndex} = seriesProps[index];
210228
dataProps = {data: data[seriesIndex]};
211229
}
212-
return React.cloneElement(child, {
230+
231+
const childProps = this._getChildProps(index, {
213232
...dimensions,
214233
animation,
215-
...(dataProps && child.type.prototype && child.type.prototype.render
216-
? {
217-
ref: ref =>
218-
(this[`series${seriesProps[index].seriesIndex}`] = ref)
219-
}
220-
: {}),
221234
...seriesProps[index],
222235
...scaleMixins,
223236
...child.props,
224237
...XYPlotValues[index],
225238
...dataProps
226239
});
240+
241+
const refProp =
242+
dataProps && child.type.prototype && child.type.prototype.render
243+
? {
244+
ref: ref =>
245+
(this[`series${seriesProps[index].seriesIndex}`] = ref)
246+
}
247+
: {};
248+
249+
return React.cloneElement(child, {...childProps, ...refProp});
227250
});
228251
}
229252
/**

packages/react-vis/src/utils/scales-utils.js

+28-6
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,24 @@ export function extractScalePropsFromProps(props, attributes) {
763763
return result;
764764
}
765765

766+
const ALL_ATTRIBUTES = [
767+
'x',
768+
'y',
769+
'radius',
770+
'angle',
771+
'color',
772+
'fill',
773+
'stroke',
774+
'opacity',
775+
'size'
776+
];
777+
778+
const defaultScaleProps = ALL_ATTRIBUTES.reduce((result, attr) => {
779+
result[`get${toTitleCase(attr)}`] = d => d[attr];
780+
result[`get${toTitleCase(attr)}0`] = d => d[`${attr}0`];
781+
return result;
782+
}, {});
783+
766784
/**
767785
* Extract the missing scale props from the given data and return them as
768786
* an object.
@@ -776,17 +794,21 @@ export function getMissingScaleProps(props, data, attributes) {
776794
const result = {};
777795
// Make sure that the domain is set pad it if specified
778796
attributes.forEach(attr => {
779-
if (!props[`get${toTitleCase(attr)}`]) {
780-
result[`get${toTitleCase(attr)}`] = d => d[attr];
797+
const titleCaseAttr = toTitleCase(attr);
798+
const getKey = `get${titleCaseAttr}`;
799+
const get0Key = `get${titleCaseAttr}0`;
800+
801+
if (!props[getKey]) {
802+
result[getKey] = defaultScaleProps[getKey];
781803
}
782-
if (!props[`get${toTitleCase(attr)}0`]) {
783-
result[`get${toTitleCase(attr)}0`] = d => d[`${attr}0`];
804+
if (!props[get0Key]) {
805+
result[get0Key] = defaultScaleProps[get0Key];
784806
}
785807
if (!props[`${attr}Domain`]) {
786808
result[`${attr}Domain`] = getDomainByAccessor(
787809
data,
788-
props[`get${toTitleCase(attr)}`] || result[`get${toTitleCase(attr)}`],
789-
props[`get${toTitleCase(attr)}0`] || result[`get${toTitleCase(attr)}0`],
810+
props[getKey] || result[getKey],
811+
props[get0Key] || result[get0Key],
790812
props[`${attr}Type`]
791813
);
792814
if (props[`${attr}Padding`]) {

0 commit comments

Comments
 (0)