Skip to content

Commit

Permalink
Cache Child Props
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Chris Thomas committed Jun 9, 2020
1 parent cce5980 commit 873febc
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 20 deletions.
14 changes: 8 additions & 6 deletions .eslintrc
Expand Up @@ -19,8 +19,8 @@
"**/dist/",
"**/es/"
],
"settings":{
"react":{
"settings": {
"react": {
"version": "detect"
}
},
Expand All @@ -31,12 +31,14 @@
},
"rules": {
"consistent-return": 0,
"max-len": [1, 110, 4],
"max-params": ["error", 6],
"max-params": [
"error",
6
],
"object-curly-spacing": 0,
"babel/object-curly-spacing": 2,
"jest/require-top-level-describe":"error",
"jest/require-top-level-describe": "error",
"react/prop-types": "off",
"prettier/prettier": "warn"
}
}
}
38 changes: 30 additions & 8 deletions packages/react-vis/src/plot/xy-plot.js
Expand Up @@ -20,7 +20,7 @@

import React from 'react';
import PropTypes from 'prop-types';
import equal from 'deep-equal';
import equal from 'lodash/isEqual';

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

Expand Down Expand Up @@ -188,6 +188,22 @@ class XYPlot extends React.Component {
}
};

_childPropCache = Object.create(null);

/**
* Memoizes the props of the child.
* This is keyed off of the childs 'key' property or defaults to its index.
* @param {number} index The index of the child
* @param {object} newValues The childs props
*/
_getChildProps(index, newValues) {
const key = newValues.key || `@@series-${index}`;
const cached = this._childPropCache[key];
if (!equal(cached, newValues)) {
this._childPropCache[key] = {...newValues};
}
return this._childPropCache[key];
}
/**
* Prepare the child components (including series) for rendering.
* @returns {Array} Array of child components.
Expand All @@ -201,6 +217,7 @@ class XYPlot extends React.Component {
const children = React.Children.toArray(this.props.children);
const seriesProps = getSeriesPropsFromChildren(children);
const XYPlotValues = getXYPlotValues(props, children);

return children.map((child, index) => {
let dataProps = null;
if (seriesProps[index]) {
Expand All @@ -209,21 +226,26 @@ class XYPlot extends React.Component {
const {seriesIndex} = seriesProps[index];
dataProps = {data: data[seriesIndex]};
}
return React.cloneElement(child, {

const childProps = this._getChildProps(index, {
...dimensions,
animation,
...(dataProps && child.type.prototype && child.type.prototype.render
? {
ref: ref =>
(this[`series${seriesProps[index].seriesIndex}`] = ref)
}
: {}),
...seriesProps[index],
...scaleMixins,
...child.props,
...XYPlotValues[index],
...dataProps
});

const refProp =
dataProps && child.type.prototype && child.type.prototype.render
? {
ref: ref =>
(this[`series${seriesProps[index].seriesIndex}`] = ref)
}
: {};

return React.cloneElement(child, {...childProps, ...refProp});
});
}
/**
Expand Down
34 changes: 28 additions & 6 deletions packages/react-vis/src/utils/scales-utils.js
Expand Up @@ -763,6 +763,24 @@ export function extractScalePropsFromProps(props, attributes) {
return result;
}
const ALL_ATTRIBUTES = [
'x',
'y',
'radius',
'angle',
'color',
'fill',
'stroke',
'opacity',
'size'
];
const defaultScaleProps = ALL_ATTRIBUTES.reduce((result, attr) => {
result[`get${toTitleCase(attr)}`] = d => d[attr];
result[`get${toTitleCase(attr)}0`] = d => d[`${attr}0`];
return result;
}, {});
/**
* Extract the missing scale props from the given data and return them as
* an object.
Expand All @@ -776,17 +794,21 @@ export function getMissingScaleProps(props, data, attributes) {
const result = {};
// Make sure that the domain is set pad it if specified
attributes.forEach(attr => {
if (!props[`get${toTitleCase(attr)}`]) {
result[`get${toTitleCase(attr)}`] = d => d[attr];
const titleCaseAttr = toTitleCase(attr);
const getKey = `get${titleCaseAttr}`;
const get0Key = `get${titleCaseAttr}0`;
if (!props[getKey]) {
result[getKey] = defaultScaleProps[getKey];
}
if (!props[`get${toTitleCase(attr)}0`]) {
result[`get${toTitleCase(attr)}0`] = d => d[`${attr}0`];
if (!props[get0Key]) {
result[get0Key] = defaultScaleProps[get0Key];
}
if (!props[`${attr}Domain`]) {
result[`${attr}Domain`] = getDomainByAccessor(
data,
props[`get${toTitleCase(attr)}`] || result[`get${toTitleCase(attr)}`],
props[`get${toTitleCase(attr)}0`] || result[`get${toTitleCase(attr)}0`],
props[getKey] || result[getKey],
props[get0Key] || result[get0Key],
props[`${attr}Type`]
);
if (props[`${attr}Padding`]) {
Expand Down

0 comments on commit 873febc

Please sign in to comment.