Performance: Avoiding wasteful renders
See original GitHub issueUse case
I’m adding interaction to a chart, so when the user hovers over the chart, the closes coordinate will “light up”.
Example
const data = [
{ x: 1502282820000, y: 0 },
{ x: 1502282880000, y: 480.07448979591834 },
{ x: 1502282940000, y: 210.27743589743585 },
{ x: 1502283000000, y: 437.2161836734694 },
{ x: 1502283060000, y: 178.02835999999996 },
{ x: 1502283120000, y: 462.68808163265305 }
];
class PerfTest extends Component {
state = {
markIndex: null
};
// Just pseudocode - not called anywhere
// this can be achieved with the Voronoi component,
// but is out of scope for this example
onHover(index) {
this.setState({
markIndex: index
});
}
render() {
const { markIndex } = this.state;
return (
<XYPlot width={800} height={300} xType="time">
<XAxis tickTotal={10} />
<LineSeries xType="time" curve={'curveMonotoneX'} data={data} />
{markIndex !== null && <MarkSeries data={[data[markIndex]]} />}
</XYPlot>
);
}
}
Performance problem
When this.state.markIndex
changes, PerfTest
should re-render. However, I’ve noticed that every child of XYPlot
also re-renders. In the example above, I would expect only MarkSeries
to be re-rendered. Not XAxis
or LineSeries
.
Demo
I’ve created two demonstrations of the problem - one without optimizations, and the other with optimizations. Please allow 5 seconds for the performance test to run, and then check the results in the console.
Codepen without optimizations https://codepen.io/sqren/pen/WEYYLY?editors=0011
Total render time: 200ms Wasteful renders: 500 Wasted time: 270ms
Codepen with mutation optimizations https://codepen.io/sqren/pen/xLQmWL?editors=0011
Total render time: 140ms Wasteful renders: 250 Wasted time: 60ms
The optimized version makes half the amount of needless renders, and is 30% faster.
Question
I don’t think it’s a good approach to mutate properties, when passing them to child components. If the component is an instance of React.PureComponent
it will not update correctly, so I expect weird results could come out of this.
On the other hand, I do like the performance gains in the optimized version. What is your take on this?
Issue Analytics
- State:
- Created 6 years ago
- Reactions:8
- Comments:8 (5 by maintainers)
I’ve run into similar performance issues with implementing a crosshair on the chart. It’s particularly problematic in these spots, where the chart is expected to update at a high FPS but can’t keep up because it’s re-rendering lines, etc… that haven’t changed.
We worked around this by creating two charts that are positioned over each other - one for the crosshair and the other for the line series. Obviously that is a major hack!
It’d be nice if the individual series supported being
pure
components or even allowed a prop for comparison (say in the case of using Immutable for data storage, you might want to useImmutable.isEqual
).I cannot believe this issue has not yet been picked up/resolved. The performance on a stacked bar chart with crosshair is dreadful when highlighting the render updates via the React dev-tools.