React Hooks: Why We should Embrace it

The React team made quite an announcement when they revealed hooks in React. Hooks allow functional component to have state, access to lifecycle (called effects), context, and other stuffs. The community seems to have mixed opinions and some concerns about what this means for React moving forward. I played around with hooks during the weekend, and these are some of the reasons why I think hooks are good idea.

No more wrapper hell

Typical thing that happens in React app

If you are working with React, the picture above is probably awfully familiar. Until now, the main way to inject reusable logic to our component is by wrapping it in another component, usually achieved by creating an HOC or utilising the render props pattern.

With hooks, we can inject a reusable logic into our component without having to create HOC or use the render props pattern to do it.

For example, let’s say we want to create a counter, with simple increment and decrement handler. Because this feature might be used in a lot of place, we want it to be easy to be used by other components. This is how the implementation might look like using HOC.

using HOC

And… this is how it looks with hooks.

No classes, no wrappers. Component can simply use the hook that contains the logic that it needs. The hook can expose APIs needed by the Component.

Effect Hook

Currently, when we want to do something after a render is done, we would need to put the logic inside componentDidUpdate. But, because componentDidUpdate doesn’t get called after the initial render, we would need to implement the same logic inside componentDidMount as well.

Need to handle in both didMount and didUpdate. (source: React docs)

Apparently, there is a hook for this, it is called useEffect. Basically, effect is something that will be called after every render. The code above can be simplified like this.

Logic in one place. (source: React docs)

You might be thinking that it might be costly to do effect after every render, and you are probably right. The React team has thought about this and provided us with a mean for optimisation. The useEffect hook also accept an array as the second argument. It will only run the effect again if the values in the array are different compared to the previous effect call.

Easy optimization. (source: React docs)

But, another thing that is great about effects is that they are deferred after the browser layout and paint process. This allows the UI to stay responsive. Consider this badly implemented hook for example:

Observant readers will notice that this will cause the Component to keep re-rendering because the state is being updated after every render. This is exactly what happens when you call setState in componentDidUpdate. But, since useEffect is deferred, the app will still be responsive to user inputs, even if it keeps re-rendering!

If you need your effect to not be deferred, there are alternatives such as useLayoutEffect and useMutationEffect. You can read more about them on React docs.

Allow your code to be minified better

This, in my opinion, is by far the biggest reason why we should embrace hooks in React.

Hooks allow us to write functional components exclusively, without needing to write class-based components. JavaScript minifiers does not work well with JavaScript classes. This is because JavaScript classes aren’t statically analysable, thus could not be minified safely. If this is not familiar to you right now, this video from Chrome HTTP203 series might help giving some insights regarding this matter.

At the first part of this writing, I provided 2 gists that implement counter, one with HOC, and another one with Hook. Let’s see how the generated bundles compare. I have put 2 gist links that contains the generated bundle (using webpack) below, you can take a look at them.

usingHOC.bundle.js (3.5 KiB minified, 174 lines)
usingHook.bundle.js (2.47 KiB minified, 150 lines)

Other than the file sizes and the number of lines of code, notice that we still have some variables named as handleDecrement, onDecrease, etc. on the usingHOC.bundle.js gist. These variables could not be minified because we are using JavaScript classes. If you search for those variable names in usingHook.bundle.js gist, you will not find any.

1 KiB difference between these examples is actually quite surprising. You can expect bigger differences if your React app is bigger in size.

Summary

Hooks are powerful and quite mind-shifting addition to React. It allows developers share logic without creating a wrapper for everything. It allows our generated bundle to be smaller as well, which means a lot for developers working on the frontend side of the web. Smaller bundles are always better.


You can learn more about hooks by watching React team talk at ReactConf and reading about it from React docs.