There is a guide to increase React performance. The advanced tip will increase speed by 20 times.
Rendering a list of some elements in a page is a common task for almost any web-app. In this post I would like to show how to improve performance for that case.
For a test example we will create app that draws a set of targets (circles) on the <canvas> element. I will use Redux for a data storage. But these tips can be applied for many other state managing approaches. Also, you can use these tips with react-redux, but for a clear explanation I will not use it.
Let me start from store definition.
Then define our application rendering. I will use react-konva for canvas rendering.
The result of this application will be:
Now let’s create a simple test script that will run several updates on one target:
Let’s run test script for the app without any optimisations. On my machine, an update will take ~21ms.
This time doesn’t include canvas drawing, only redux + react code because react-konva is drawing objects only on the next animation frame tick. We are not interested in a canvas optimisation right now, it can be a subject of another post.
So ~21ms for 1000 elements is pretty good performance. If we update elements rarely we can keep this code the way it is.
But I had a case where I need to execute update very frequently (on every mouse move during drag&drop). For 60 FPS animation, each update should take no more than 16ms. So 21ms is not so good for this case (plus will have canvas drawing).
How can we optimise rendering?
1 Don’t update unchanged elements
This is a first rule to improve React performance. All we need is to implement `shouldComponentUpdate` for Target Element:
Result for this update (http://codepen.io/lavrton/pen/XdPGqj):
Wow. ~4ms vs 21ms. This is much better. But can we do more? In my real app even after this optimisation the performance was bad.
Now take a look into “render()” function of App component. The thing I don’t like in this code is that `render()` of app component will be called on EACH update.
That means we have more that 1000 calls for React.createElement for each target. In this case, it works fast but in larger apps it can be slow.
Why should we rerender the whole list if we know that only particular components are updated? Can we just directly update them?
2 Make child components smarter
The idea is simple:
- Don’t update the app component if a list has the same number of elements and order of elements is the same
- Children components should update itself if data is changed
So “Target” component should subscribe to store and track changes:
And implement “shouldComponentUpdate” for App component:
Result after that changes (http://codepen.io/lavrton/pen/bpxZjy):
0.25ms for an update is much better now.
About 1.5x faster than the previous result (and difference will be much more if you have more elements). And code is much simpler:
Do you have performance issues with your web-app? I can help you.