
Performance Engineering with React, Part 1 - sajithw
http://benchling.engineering/performance-engineering-with-react/
======
avolcano
I've been using React to make a 60fps music game, and this article covers
basically all of the issues I ran into:

\- Originally, the game was rendered with SVG elements, so it was very
important to use the shouldComponentUpdate hook to ensure elements weren't
rendering unnecessarily (and using CSS transformations to position them where
possible, as that's way faster than updating SVG coordinates!)

\- I had something similar to the function.bind problem since some of my
components had a map of hotkey handlers that I was (naively) returning from a
`getHotKeyHandlers` function, meaning the handlers were redefined every
render.

\- I wasn't caching/memoizing calculations done to the Redux state as well as
I should have (Reselect is very useful for this!)

I ended up deciding SVG wasn't fast enough for my use case and rewriting the
core game loop rendering to use Canvas, which was so much faster that I could
be a lot lazier about optimizing things. Everything around the canvas is still
rendered through React components (i.e. in game UI and menu screens), and the
state is still handled through Redux. It's a very fun way to write a game :)

~~~
untog
Do you think React Canvas is a thing you could have used?

[https://github.com/Flipboard/react-
canvas](https://github.com/Flipboard/react-canvas)

I've still not had a chance to play around with it, but the Flipboard mobile
site looks phenomenal.

~~~
avolcano
That looked interesting but I didn't need the most important functionality it
provides (click/touch handling, fancy text rendering, etc) so I stuck with
just using the Canvas API. It's pretty simple to do in React:
[https://gist.github.com/thomasboyt/bcc496c823a01ac5f648](https://gist.github.com/thomasboyt/bcc496c823a01ac5f648)

~~~
simonw
I might be missing something here: what benefit does React bring in this
example? If you're using canvas to render without any kind of virtual DOM, why
use React at all?

~~~
seivan
Can't you combine? Thinking it could be used for UI. Makes sense when you need
more support, like localisation and other builtin stuff. Just guessing.

------
iyn
Thanks for the valuable tips!

Currently, my biggest 'bottleneck' when developing React applications is
managing complex forms. Right now I'm using redux-form [0] which is a great
tool, but not very performant on dynamic deep/complex forms (more info and
partial hacks here: [1]).

Other than that, I don't have performance problems, but I'm curious when will
I hit Redux limitations (single store sounds great from the conceptual point
of view, but I'm not sure about the performance one). Also, can second
ImmutableJS recommendation, after a while of using it's completely natural to
use.

[0] [https://github.com/erikras/redux-form/](https://github.com/erikras/redux-
form/)

[1] [https://github.com/erikras/redux-
form/issues/529](https://github.com/erikras/redux-form/issues/529)

~~~
danmaz74
> single store sounds great from the conceptual point of view, but I'm not
> sure about the performance one

But the Redux "single store" is actually a composition of multiple stores,
each with its own reducer function. Performance-wise, it's actually better
than vanilla Flux, because, when an action causes N stores to change with
vanilla Flux, you can get up to N renders of your components (depending on how
many stores they subscribe to). At least, with Redux there is only one render
when the whole store has been updated.

~~~
seivan
When I was looking around and comparing I think most allowed for some form of
aggregation and syncing them into one call. Not sure though. Still learning.

------
dmbass
The biggest performance issue I've encountered is with long lists. The most
basic implementation means you will have to instantiate a new component for
every item in the list even if only one of them has changed. I haven't spent
that much time looking into it, so the bottleneck might be function binding (I
hadn't thought of that before) but if anybody has an approach to this any
ideas are appreciated. Maybe only pass an id as a prop and grab the rest from
context?

~~~
saifelse
I'm going to cover this in my next post, but I've found that using
PureRenderMixin with fairly large number of items (~100s) works. The non-
trivial step is often identifying why your subcomponents are still re-
rendering, which I solved by writing a mixin that logs to the console what
props/state is deep equal but not shallow equal (i.e. where PureRenderMixin
should theoretically work).

But I agree, it's still not perfect. You avoid doing the more expensive
virtual DOM comparison, but you still have to iterate over all the items to do
the PureRenderMixin checks. And it is still O(n) time, just with a smaller
constant.

Another solution is to not actually render all the children, just the ones
that are visible on the screen, i.e. using some React implementation of
infinite lists (see: [https://facebook.github.io/fixed-data-
table/](https://facebook.github.io/fixed-data-table/) )

Another idea that I've been thinking about is to arbitrarily fragment your
list into lists (possibly of fixed size, or a fixed number of fragments). Each
fragment gets its own subcomponent, so we can avoid rendering fragments that
haven't changed. For example, instead of a list of 100 items, we treat it as
10 lists of 10 items. If we change one item, we end up instantiating 10
components, and then recursing into the single fragment that has changed,
instead of over all 100 items.

~~~
dmbass
I've thought about doing the list of smaller lists but it could cause issues
with the DOM (if you care about it) since components must return a single
element. Will look into that fixed data table.

~~~
STRML
See also react-list ([https://github.com/orgsync/react-
list](https://github.com/orgsync/react-list)), which does a surprisingly good
and hassle-free job of rendering partial lists.

------
amelius
I want to see an article which shows how to code a fast rich text editor in
React.

I tried to implement one by representing the text as a long list of character
components, thinking react could handle this by only executing small
incremental updates, but the whole thing became slow anyway.

Am I missing something, or is react not up to this task?

~~~
saifelse
Building a fast rich text editor in React is no easy task, and would be at
least a series of articles :-P. At Benchling we've built a fairly fast rich
text editor in React--but it was a considerable amount of work and still
requires quite a bit more work. You may have heard that Atom was originally
written in React, but they abandoned it to avoid its overhead[0]

There are open-source projects worth looking at like Ritzy[1] which is quite
fast and written in React from what I've read.

As per your specific issue, I've found that using PureRenderMixin with each
line of text represented as a component works for hundreds of lines, but this
still ends up with performance issues as you scale to thousands of lines.
Using a list of one-character components will run into performance issues much
sooner as there is per-component overhead.

[0]
[https://github.com/atom/atom/pull/5624](https://github.com/atom/atom/pull/5624)
[1] [http://ritzyed.github.io/ritzy/](http://ritzyed.github.io/ritzy/)

------
dangoor
I don't see enough mention of this, but if you want immutability (to make
shouldComponentUpdate easy) icepick is a better choice than Immutable.js for a
great many applications:

[https://github.com/aearly/icepick](https://github.com/aearly/icepick)

It's tiny but offers a number of utilities that are more convenient than what
you get with ES6 spread syntax. The tradeoff with Immutable.js is that if you
have huge single objects (arrays with many elements, objects with many keys),
then making copies will get more expensive than with Immutable. Otherwise,
icepick is all win.

------
saifelse
Author here, happy to answer any questions!

~~~
syz
With the ES6 class syntax, is it possible to avoid the function.bind/anonymous
function issue (and subsequent need for the whole IntermediateBinder thing) by
redefining methods that will be passed into a subcomponent in the constructor
to their bound equivalent? That is, in the constructor: `this.foo =
this.foo.bind(this)` and in render: `<SubComponent foo={this.foo} />`?

~~~
saifelse
What you described is the current replacement for auto-bind (that
React.createClass used to do for you). The issue arises when you have not just
one SubComponent, but n SubComponents that require the parent method bound to
the subcomponent's index, e.g. you have a deleteItemAtIndex method, and you
only want to expose {deleteItem: deleteItemAtIndex.bind(this, i)} to each
child component. ES6 React classes don't have any special way of handling
this.

To re-iterate the possible solutions I've considered:

\- Don't pass in a bound method; give the component the unbound method and its
index and the child component can call it with the index passed in itself. \-
Generalize this to a re-usable intermediary component that does for you (it
does feel a bit dirty) \- Write your own bind function that annotates the
bound function with original function + params allowing you to do a "deep"
equality check, and then use a variant of PureRenderMixin that does this
"deep" equality check.

Honestly, all of the solutions feel a bit hacky, but I've gravitated towards
the first and second options.

~~~
syz
Ah, of course. Thank you for the clarification.

------
sergiotapia
These will _probably_ be useful but I did not understand any of the terms
mentioned in the article. I guess I haven't hit any major bottlenecks yet.
Bookmarked!

------
STRML
I just went through a rather large profiling/optimization run on the my site,
BitMEX (we're a Bitcoin derivatives exchange). Performance is paramount in
trading, so our site has to be fast. Here's some additional tips:

0\. shouldComponentUpdate (SCU) is everything. Consider creating a base
React.Element extension class. I define a base shouldComponentUpdate and some
useful utilities on it. Having it in one place is really useful because you
can log its output from every component and watch how your whole application
updates. It makes it easy to see useless rerenders.

\- One very helpful addition in our app has been a static 'SCUSelector'
property, which tells our shallow shouldComponentUpdate to ignore certain
props/state/context. This helps in combination with rich componentWillMount()
or getInitialState() functions to precalculate expensive data that updates
rarely/never.

1\. It seems the `connect(component, selector)` model [0] encouraged by Redux
to hook up application data to deep(er) components is much better for
performance. You want to avoid renders in as many tree branches as possible.
To this day, the root element (`<App>`) still holds most of our data and fans
it out to the Router, Header, Sidebar, etc. This root-level render must be
_extremely_ fast because it runs on every tick. Hoisting any and all data that
can be made constant is a huge help.

2\. We saw massive (50%+) performance gains from Babel's constant-elements and
inline-elements optimizations [1]. Careful with it - there's is a nasty bug
[2] that _only manifests in production_ you need to be aware of if you're
deploying this.

3\. Immutable-JS is kind of a wash. I'm not a big fan of the API or how easy
it is to nest mutable objects and arrays inside immutables. The new
array/object spread syntax in ES6 makes it easier to construct unique objects
every time data updates, so you can do a shallow shouldComponentUpdate.

4\. Watch out for function identity because it will blow SCU [3]. Either
ignore the property explicitly, or use a binding helper like the one I posted
on that issue [4].

5\. If you're doing expensive data computation, such as
update/insert/delete/image on websockets, profile it. If you're accidentally
causing deopt, you'll feel it. Make sure the libraries you use don't cause
deopt either. A few simple tweaks [5] can give you 2-10x performance boosts on
hot functions [6].

6\. If you haven't already, watch videos on how V8 optimizes. It will help you
write fast code in the future.

7\. Keep watching your app! The new React devtools can highlight components as
they update. This is really useful to see what work is being done and how you
can improve.

\---

Links:

0\. [https://github.com/rackt/react-
redux/blob/master/docs/api.md...](https://github.com/rackt/react-
redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-
mergeprops-options)

1\. [https://babeljs.io/docs/plugins/transform-react-inline-
eleme...](https://babeljs.io/docs/plugins/transform-react-inline-elements/)

2\.
[https://github.com/facebook/react/issues/5138](https://github.com/facebook/react/issues/5138)

3\.
[https://github.com/facebook/react/issues/5197](https://github.com/facebook/react/issues/5197)

4\.
[https://github.com/facebook/react/issues/5197#issuecomment-1...](https://github.com/facebook/react/issues/5197#issuecomment-177991647)

5\.
[https://github.com/petkaantonov/bluebird/wiki/Optimization-k...](https://github.com/petkaantonov/bluebird/wiki/Optimization-
killers)

6\. [https://github.com/AmpersandJS/ampersand-
state/pulls?utf8=%E...](https://github.com/AmpersandJS/ampersand-
state/pulls?utf8=%E2%9C%93&q=is%3Apr+strml)

------
davnicwil
> This post is for those of you with a complex React application. If you're
> building something smaller, you might not need to focus on performance yet.
> Don't prematurely optimize! Go build things!

This is bit meta, but it's really, really awesome to see an article on
performance begin with this. Well done author :-)

It instantly inspires confidence that the material to follow is worthwhile
reading. Knowing the author has started out with this philosophy I trust more
that what's covered will focus on things that actually matter, rather than
just being a crawl through every and any technique or quirk that they've come
across, regardless of its relative impact.

Performance is one of those things where more is obviously better, all other
things equal, but that last 20% of effort invested is almost always time that
could be better spent improving other aspects of the average _use case_ of any
given product, let alone the average product.

------
jwr
TLDR for ClojureScript users: most techniques described here do not apply to
you. Whatever React library you use (Rum, Om, Reagent, or other), most work
has already been done for you through immutable data structures. Unless you go
out of your way to create lots of components that react to something different
than their parameters, shouldComponentUpdate will be handled quietly behind
your back and you'll get impressive performance right out of the box. And no
need to even learn about the differences between deep/shallow comparisons,
either.

~~~
grayrest
This is true unless you're using cljs-datetime. The library's use of goog.date
objects under the hood means that storing one in your state tree invalidates
the fast equality checks that everything in the clojurescript space is
assuming.

