React Hooks — Slower than HOC?
Now that the much anticipated React Hooks API has been officially released, I was finally able to scratch the itch of comparing its execution speed compared to good old HOCs. And the results surprised me!
Amidst all the excitement over shiny new Hooks, the trusty old HOC may have been unnecessarily vilified. Right off the bat I will say that my simple benchmarks showed HOCs may still be faster, despite the “wrapper hell” that it’s been recently much maligned for. Of course, if you find that my test is flawed, I will appreciate being corrected.
The Test App
I contrived a basic test app that renders 10,000 instances of a functional component that has 3 state values, and an effect that sets the 3 state values once after the first render. The main component logs the time elapsed from instantiation of the root component to the time it finishes rendering the 10,000 items. For this, it also uses an effect.
I then created 2 versions of the test app, one using Hooks and the other using HOCs (using the Reactor Library that I recently published: https://github.com/arnelenero/reactorlib#reactor-library).
The Hooks Version
import React, { useEffect, useState } from 'react';
import { render } from 'react-dom';const array = [];
for (let i = 0; i < 10000; i++) array[i] = true;const Component = () => {
const [a, setA] = useState('');
const [b, setB] = useState('');
const [c, setC] = useState('');
useEffect(() => {
setA('A');
setB('B');
setC('C');
}, []); return <div>{a + b + c}</div>;
};const Benchmark = ({ start }) => {
useEffect(() => {
console.log(Date.now() - start);
}); return array.map((item, index) => <Component key={index} />);
};render(<Benchmark start={Date.now()} />, document.getElementById('root'));
The HOC (Reactor Library) Version
import React from 'react';
import { render } from 'react-dom';
import { compose, withState, withEffect } from '@reactorlib/core';const array = [];
for (let i = 0; i < 10000; i++) array[i] = true;const _Component = ({ a, b, c }) => {
return <div>{a + b + c}</div>;
};const Component = compose(
withState({
a: '',
b: '',
c: ''
}),
withEffect(({ setA, setB, setC }) => {
setA('A');
setB('B');
setC('C');
}, true)
)(_Component);const _Benchmark = () => {
return array.map((item, index) => <Component key={index} />);
};const Benchmark = compose(
withEffect(({ start }) => {
console.log(Date.now() - start);
})
)(_Benchmark);render(<Benchmark start={Date.now()} />, document.getElementById('root'));
The Test Setup
Tests were run on an early 2015 12" Macbook (1.1GHz Core M, 8GB RAM) running MacOS Sierra 10.12.3 and Chrome 71.
Both versions are on React 16.8.1.
The Test Results
I captured the results of 10 test runs on MacOS Chrome, all of which show a clear winner.
Rendering Time in millisecondsRun# Hooks HOCs
-----------------------------
1 2197 1440
2 2302 1757
3 2749 1407
4 2243 1309
5 2167 1644
6 2219 1516
7 2322 1673
8 2268 1630
9 2164 1446
10 2071 1597
But don’t take my word for it. You can run the two versions I posted above and see for yourself.
Conclusion
If the difference in rendering speed would be crucial to your use case (e.g. looped instances of component), these figures show that you may have to reconsider using HOCs instead. For typical use cases, though, the difference may not be significant enough to sway your decision.
Other Considerations
The choice between Hooks and HOC might not be the no-brainer that we initially thought it to be. Apart from what I covered here, there are other factors that affect this choice, such as your specific strategy for code reuse. Good thing is, we are not forced to pick just one of them; we can use both, with careful judgment on which components should prefer one over the other.
In spots where you would need HOCs instead, you might want to check out my Reactor Library (https://github.com/arnelenero/reactorlib#reactor-library). No, it’s not only about functional components; it has a whole lot of other things that can help you simplify your React/Redux development. Feel free to use, it’s yours as much as mine.