Arrow functions in React
This topic is already well discussed and the intent of this article is to share how I prefer to use arrow functions in React and my view on PureComponent optimizations.
Function Components
In function components, we have currently no other choice but to either pass the callback directly from the props to the child component or to create an inline arrow function. You may want the latter if you need to control the arguments passed to the original callback.
You need to be aware of 2 things in this example:
- You generate a function on every render, which will obviously have a new reference.
- If the component you pass this generated function to is extending PureComponent, it will not be able to bail out on rerendering, even if the actual data has not changed.
Using inline arrow functions in function components is a good way to achieve some decoupling.
Class-Based Components
In class-based components we have a choice: either to generate an inline callback or to use a class method. I usually go for class methods, just because I prefer to keep JSX as clean as possible, but the main benefit of using methods is to generate the callback only once when React instantiates the class. This gives you an opportunity to optimize a subtree of a complex child component that extends PureComponent.
Optimizing rendering
It is completely irrelevant if you use PureComponent everywhere or not. In the most cases it simply does not matter, so why bother? In theory, you could even make your application a bit slower since shallowEqual comparison will run on every PureComponent update and it will fail to bail out in the most cases.
It is hard to get the benefits of PureComponent because it is hard to make sure that you don’t create new references by accident. If you really need to optimize a subtree, pick your component wisely and really make sure it never creates new references in the render method. Never forget that PureComponent is an optimization and without it React is still fast enough for 99% of cases.
Avoid generating new references in render method if you really need the PureComponent optimization to work.
Arrow functions in class properties
Since arrow class properties are still in a proposal stage, it is understandable that official React documentation doesn’t use them. For application code though, it is really annoying to write methods and then to write binding for each of them. They are so handy that the downsides of not being part of the standard yet or being slower than methods don’t outweigh the DX benefit.
Arrow functions in class properties are way easier to write and to read than a method with a bind call inside of a constructor.
Arrow functions in class properties performance
Arrow class properties are slower, but only on a micro level. Babel moves them to the constructor, so they are not reused between the class instances. Unless you are going to instantiate millions of components, the difference will be a few milliseconds for hundreds or even thousands of components. I am not going to create a benchmark to prove that since I would be basically measuring the cost of a function creation upon instantiation.
There is still a hope, that arrow functions in class properties will get into the standard and native implementation will be very fast.
Arrow functions in class properties override
Since they are not defined on the prototype, you can not override them when subclassing a component. The point though is that React doesn’t want us to subclass components. React recommends to either use props or higher order components. Over years of working with React, I never needed to subclass a component and I never saw a good use case for doing so. Also, since we use arrow class properties to pass them as callbacks to child components, I consider them a private implementation detail, which should never be used as a public/protected API.
Never subclass a React component, unless it is the official React.Component base class.
To sum up, I mostly use function components and I use inline arrow functions. I rarely use class based components, but when I do then for 3 reasons:
- To use lifecycle hooks.
- To reuse child props references.
- To use PureComponent.
I keep them really small and focused on what I can do in a class-based component only. I move everything else to function components.