The Startup
Published in

The Startup

Custom Hooks in React: Hands-on

Custom hooks are great to add flexibility to your code and reuse logic, with the help of the alreay existing react hooks in a creative way.

Through this blog post we will have a look at how to create custom hooks, and just how flexible we can be with them. To demonstrate this flexibility, we will use a pretty ridiculous use case: a Witcher needing a potion refill to boost his stats.

Let us create a local react (typescript) project:

We’ll remove the pre-populated stuff from our App.tsx file, so that only the following shell remains:

Cool, now let us get to defining our logic a little.

First, let us create a few interfaces to lay down the foundation for what we are about to do. In your App.tsx file, add the following interfaces right after your import statements at the top:

As you can infer, we have created interfaces to define a ‘Character’, which is the entity having some stats and potions (which can be used to boost these stats).

Let us now proceed to acquire our witcher, Geralt of Rivia. Add the following code below your interfaces:

We created the stats interface earlier, since stats for a potion and those for a character look quite similar as you can see above. We have used the hp, attack and defence keys again to indicate the boosts that the potion offers.

Now let us get to our App functional component, so we can use our webpage to display the witcher’s statistics.

What we have done above, is simply added the Geralt object we created earlier to local state with the help of the useState hook provided by React.

Besides this, we have just listed down Geralt’s stats on our page. We have used inline styling to keep things as concise as possible for the scope of this blog of course.

Try seeing these changes in your browser and it should look something like this:

Now onto the fun part, creating the custom hook.

Creating your own hooks

A custom is nothing but a javascript function, only that it will be using the already existing hooks provided by react. The other special thing about this function is that it needs to be prepended with “use”, like all other react hooks are.

Since we are creating a hook to help our witcher use potions to enhance his stats, we shall call our hook: usePotion (unsurprisingly). Our hook will only allow one potion to be used per invocation, hence usePotion and not “usePotions”.

Great, let’s next create a directory to keep our custom hook in. In your src folder, create a directory called ‘hooks’. In this directory, create a file called usePotion.tsx to store our custom hook in.

Your new directory should look like this

Now let us first create the function for our hook:

We will take in a Character and a Potion as arguments for this hook.

We will then update the Character’s current stats with the available stats from the Potion.

If you remember, earlier we had added the following interfaces in our App.tsx file:

As we exported our interfaces, we are now able to use them in our usePotion.tsx file:

The code we have so far in our usePotion.tsx file looks like:

Let us now import useState, to track the current potion and character statistics. We will do this as follows:

Let us now add a useEffect as well, which will reflect changes in state according to the currentPotion that is used.

We have added our useEffect to check if a currentPotion is used, and then to set the currentCharacter’s stats to update as per the passed potion’s stats.

I have deliberately expanded the updates made to the hp, attack and defence properties for the character to make things more verbose.

We have also added a cleanup function to always set the currentPotion to null after we are done, so that we can pass in the same type of potion again if needed. For example, if our character has two of the same potions and uses them both one after the other.

Otherwise useEffect would not detect a change to the dependency and won’t update the character’s stats if the same potion was passed twice (or more times) in a row.

But so far, we have not returned anything from this hook. We will need to return something for our use case, so that we can set the potion to be used from outside of the hook and capture the changes to the character stats as well.

We will therefore return the following two things at the end of our custom hook:

The character’s stats (currentCharacterStats), and the setCurrentPotion state update function to update the potion from outside of the hook.

The complete code for our custom hook should like this:

So from our custom hook, we exported the character’s updated stats and a function to set the current potion to be used to change these stats.

This exported function is nothing but the “setState” method: setCurrentPotion, used to update the currentPotion state.

As currentPotion is listed as a dependency, it will alos make the useEffect in our custom hook fire.

Now onto using this hook in our App.tsx file.

First, go to your App.tsx file and add an import for our custom hook. To the code which we already have in it, add the following import:

Great, now let us make an initial call to the custom hook.

We pass null as the potion initially because we do not want to use any potion yet. Instead, it would be great if we could use a potion by clicking a button.

We will do exactly this next, and hence we will create a function to update the potion with the help of setPotion (extracted above).

If you refer to our exports from our usePotion hook then you will see that setPotion will basically update the currentPotion in our hook.

We will also add a button to fire this function:

At this point, your app will look like this in the browser:

But of course, clicking the buttons will not do anything. This is because we are not using the updated stats we receive from our custom hook to update our actual character stats.

To do this, we will add the following useEffect, and list stats as its dependency:

So whenever we get new stats from our custom hook, the useEffect fires (since it has stats as a dependency) and updates our witcher state:

The complete code for App.tsx looks like this:

And there you have it, your application should now work as intended!



Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +768K followers.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Arun Kant Pant

Building things, breaking things, learning things. Frontend Engineer at The Economist Intelligence Unit.