React Hooks — Why and How

Recently the React team decided to bring Hooks into our lives. I am pretty sure that you have heard of Hooks, though there are still a lot of people that haven’t taken the time or gotten the chance to experiment with them.
In this post, I will be showing you reasons why you should be using the new Hooks in your future work. Furthermore, I will be explaining how you can use them best and hopefully motivate you to build awesome things with Hooks.


In the code examples below you will see that I am using <></> a couple of times. These are Fragments. In case you are not familiar with these, go check them out! They are awesome.

Why Hooks

TL;DR: Hooks give us the possibility to extract stateful logic which before could only be used in Class components and allow us to test this logic separately and reuse this logic.

Mixins are no more

Back in the days in order to reuse stateful logic, there were mixins.

There were a couple of problems with mixins:
Mixins introduce implicit dependencies — In short, this means that both your component could rely on a method defined in your mixin (or the other way around) and there is no way to enforce this method to be present.

Mixins cause name clashes — If you have two mixins that both define a handleKeydown method, you cannot use both and you cannot define a method with the same name on your component.

Eventually, mixins became considered harmful when we learned about Higher-Order Components

Higher-Order Components pattern

The HOC pattern is pretty powerful yet so simple and elegant.
It’s just a function that returns your component wrapped with another component.

Although it’s a great and powerful way there are some downsides too, for example using too many HOC’s could get you in wrapper hell.
There are entire libraries build around this pattern, like Recompose. Recompose made it easier to turn a dumb functional component stateful, simply by composing it with a couple of HOC’s — which in turn can get you to wrapper hell.

The problem with classes and current lifecycle implementations

As you can see in the example above we have defined our lifecycle methods: componentDidMount, componentDidUpdate and componentWillUnmount.
These lifecycle methods can of course only be defined once per component, which means that we have non-related effectful code within each one of these lifecycle methods, i.e., componentDidMount:

The fetchUser and the window.addEventListener have nothing to do with each other, yet they live the same code block. This can make class components messy and decreases code readability as complexity within your component grows.


Hooks to the rescue

With the introduction of Hooks, the use of functional components get’s promoted — This does not mean that classes are being removed from React.

Hooks are completely opt-in. You can try Hooks in a few components without rewriting any existing code.

What do Hooks solve? In class components it’s hard to reuse stateful logic between components and complex class components become hard to understand and even harder to read.

useState

Let’s say I want to have a controlled input within my component. I can create this controlled input by implementing theuseState Hook which will store the current value entered in the input and provides us with a method to update the state:

Amazing, right? we have just added a state to our functional component!
But what if we need multiple states? Don’t worry, you can!

useState is amazingly simple to use and can be passed any datatype to store in the state, for example, objects. The difference between the original class component method setState and the method provided by useState to set the state is that it does not merge objects.

useReducer

In order to deal with a complex state like a nested object, we can use useReducer.
Everyone that has worked with Redux before will notice similarities in syntax and usage:

*From the react Hooks docs

useEffect

useEffect is a lifecycle Hook for functional components that combines componentDidMount, componentDidUpdate and componentWillUnmount. useEffect is named useEffect because this is where you carry out your side effects, e.g., ApiFetching, Subscriptions or Events.

Even though it is a lifecycle method like the others, in a way it’s better than the rest. The reason for it being better is that you can make use of useEffect multiple times within a single component, which allows you to split up and keep related logic grouped together and maintaining readability of your code.

The most simple example of using useEffect, is to make our component listen to the keydown event.

As you can see we return a function inside of our effect which removes the eventListener, useEffect calls a returned function whenever it is time to clean up, like when a componentWillUnmount is called.

The second parameter in useEffect allows us to only run the effect when specific values have changed like in the following example, we only run the effect whenever the userId has changed.

Optionally the second parameter can also just be an empty array, in this case it will only execute on componentDidMount and componentWillUnmount and the effect won’t run on componentDidUpdate.

Let’s put useState and useEffect to use

Now that we’ve discussed useState, useReducer and useEffect I thought it would be nice to put some of these to use and refactor a class component to a functional component. Furthermore we will utilize the Hooks API and create a custom Hook that enables us to easily implement handling keyboard shortcuts on component level.

Let’s say we have a clock component which shows the current time and updates every second. Here we go!

Our Amazing Clock Class Component

We have a simple class component with a state containing the current time, a componentDidMount lifecycle method that creates an interval that updates the current time in the state every 1000 milliseconds and a componentWillUnmount which clears the interval when we unmount the component… Pretty straight forward.

Now the part that we actually want to refactor is:

We want to refactor the lifecycle methods above to use a single useEffect and the state to use useState so that we can refactor our class component into a functional component.

How would we do this using Hooks?
Let’s get started by importing both useState and useEffect. Let’s then turn our component into a functional component.

Now our variable time is undefined so let’s create a state called time, we will be using useState with a default value which is the current time.

We now have a state within our functional component that stores our current time! As our next step we update this every second or so as we did in our class component, let’s implement the useEffect.

Remember that useEffect acts as componentDidMount, componentDidUpdate and componentWillUnmount. In our situation, we do not want our effect to run again on componentDidUpdate so we pass an empty array as the second parameter to only run our code on componentDidMount and componentWillUnmount.
Adding to that you can see that we return a function from our effect and that we call clearInterval from within, this is us cleaning up, remember? That method gets called whenever React thinks it’s time to clean up like componentWillUnmount.

Here’s a working example of our refactored Clock component using Hooks

Our Amazing Clock Functional Component

The code looks different, shorter and much cleaner but does exactly the same, take a look at the before and after:

Our code before and after the refactor

Custom Hooks

Now that we’ve gone over the basics, let’s go ahead and create our own custom Hook.
According to the React Hooks documentation

A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks

Of course you can name your Hook whatever you like. It is just best practice to start your hook with “use”. If you start your custom Hook’s name with “use”, React’s eslint-plugin-react-hooks is able to find bugs in the code using Hooks.

A custom Hook is a great way to create reusable logic, in this example we will create a custom Hook that allows us to easily add keyboard shortcuts on component level.

Imagine we have a list of some kind, in this example, we will use a list of people portrayed in the series “Silicon Valley”, I have set up a Codesandbox that you can use to get started. As you can see there is an active item highlighted, you can click any of the other items to highlight the item.

Now let’s create and implement our custom Hook and Hook up the arrow keys so that we can navigate through this list using our keyboard.

We want to create a Hook that:

  • Stores the active keys in the state;
  • Sets an active key in the state on keydown;
  • Removes an active key from the state on keyup;
  • Returns a method to check for active shortcuts in a human-readable way, for example, “shift+enter”;

Setting up the basics

Next we will implement some logic to add an active key to our state, remove it from our state whenever it’s no longer active, create our isShortcut helper method and attach our event listeners, let’s also not forget to clean up!

We have just created a javascript function named useShortcut which adds two event listeners, one to handle our keydown and one to handle our keyup event.
On keydown, we are adding the newly pressed key to our activeKeys state, if it isn’t already active and on keyup, we remove the released key from the activeKeys state.
We’ve also created a helper method called isShortcut which accepts a string like “shift+enter” and splits these into separate keys after which it will check if all keys are currently present in our activeKeys state.
Our method returns an array containing our activeKeys array and our helper method isShortcut. And whenever React finds it’s time to clean up we remove our event listeners.

Great! We have just created our own custom Hook, let’s put it to use in our Codesandbox from earlier where we display a list of people.

We can use our new custom Hook by importing it and adding a useEffect to our component from which we call our helper method like previewed in the following example:

I have created a working version in Codesandbox so you can see the end result:

Now I have got to be honest, our useEffect looks pretty messy… Remember that I told you that you can use useEffect as many times as you want inside a component? We could split this up into 3 different useEffects but instead, I think we should update our custom Hook and create a custom effect which we can just implement.

What does a custom effect look like?

And behind the scenes, it’s not a lot more than a method that uses our custom Hook and useEffect and calls our callback method whenever a shortcut matches, here’s the source:

So to put it all together, I have created a Codesandbox that uses our new custom effect, take a look at the source!

Much cleaner eh..?


I hope you have enjoyed reading about the Hooks that we have discussed.
The Hook we have created in the above written examples is available on NPM.
I will soon be posting a next part in which we will go over a bunch of other Hooks.

Thanks for reading :)