Understanding Custom React Hooks by Using Them

What are they? and Why and How to use them.

Angad Singh
Mar 22 · 5 min read

React 16.8 came with the ability to use hooks in React that gave us the ability to enhance functional components in such a way that they could do anything a class component could do through useState and useEffect hooks. But a slightly overlooked capability was to create your own custom hooks.

Photo by James Pond on Unsplash

What is a custom hook?

Why should you use hooks?

If you can contain the functionality of a few components in a separate function — a hook, you just have to test this hook to ensure that this functionality of your code is working fine. This makes writing small unit tests a lot easier. Instead of testing a whole component, you can test that the hook is implemented correctly and then have separate tests to ensure that the component is importing and using the hook.

You could even package “common” functionality that your organisation uses into an NPM package so this hooks repository can be installed in different micro-applications throughout the organisation and ensure standardisation.

How can I use custom hooks?

npx create-react-app your-app-name

Once you have your react project ready, let’s alter App.js to look like this.

// App.js
import React from 'react';
import useRandomPokemonImage from './useRandomPokemonImage';

const App = () => {
const imageUrl = useRandomPokemonImage();

return (
<div style={{ display: 'flex', height: '100vh', justifyContent: 'center', alignItems: 'center' }}>
<img src={imageUrl} alt=""/>

export default App;

What are we doing here? We are using a custom hook that we have not created yet. But the returned value of that custom hook is clearly the url to the image of that Pokémon. We are displaying this image while it’s wrapped in a div tag so we can use flexbox to center the image on the page.

Of course, your editor as well as React will now complain about a missing file called useRandomPokemonImage . Let’s go ahead and create that in the same folder.

import { useState, useEffect } from 'react';

const TOTAL_POKEMON = 151;

const useRandomPokemonImage = () => {
const [image, setImage] = useState(null);

useEffect( () => {
const fetchPokemon = async () => {
const randomPokemonIndex = Math.ceil(Math.random() * TOTAL_POKEMON);
const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${randomPokemonIndex}`);
const data = await response.json();
const pokemonImage = data.sprites.front_default;
}, []);

return image;

export default useRandomPokemonImage;

Before you start going through the code. Tell me how would you do this in a normal class component? It’s pretty easy you would need 3 pieces of code.

  1. The first one would be state = { imageUrl: null } .
  2. Then you would need a componentDidMount method, so after the Page component is loaded, you make a fetch call to the Poké API and after awaiting for the response, you would do this.setState({ imageUrl }) to update the state.
  3. All the while your render function will have an img tag that looks like:
    <img src={this.state.imageUrl} alt="" />

Of course since we are using functional components, what we would need is useState and useEffect . So in a functional component the steps would be as follows:

  1. You would initialise the variable and setter with useState as follows:
    const [imageUrl, setImageUrl] = useState(null) .
  2. Then to only fetch the image url when the component mounts you would need useEffect . The first argument here would have to be the actual fetch function itself where you retrieve the image url from the api and then do useState(response.imageUrl) . And the second argument would be [] — an empty array to indicate to the useEffect hook that there are no dependencies for which this function should be re-called.
  3. Similar to the class component your return value must include an img tag like:
    <img src={imageUrl} alt="" /> .

Now let’s look at our custom hook and see how it is implementing this same functionality.

As a nerd, I know that the first generation of Pokémon had only 151 Pokémon and in my opinion that is the only generation that matters. So I want to only fetch a Pokémon from that generation. The way the Poké API works is that, you can give the ID of that Pokémon and get details about that Pokémon. Since we have decided to only get up to the first 151 Pokémon’s, I will use Math.random to get a random number between 1 and 151 (inclusively) and then use the browser’s native fetch feature to get the details of this Pokémon. After retrieving the image from the API we are using the setter method from the useState call. This functionality is exactly how we described earlier a functional component would achieve this functionality without custom hooks.

The only difference we can see here in this hook is that it is not returning jsx . Instead it is returning us the state variable imageUrl . This is a key difference because now we can use it’s returned value and plug it into any functional component.

Let’s go back to App.js and look at it’s 6th line:
const imageUrl = useRandomPokemonImage();

The hook that we created is very easily used in this component. And then we can reference this variable wherever we need and use it. In our case we are simply using it as the src attribute for our img tag.

Photo by MI PHAM on Unsplash


The Startup

Medium's largest active publication, followed by +610K people. Follow to join our community.

Angad Singh

Written by

Talking about money, tech and how to make money from tech. Real estate investor. Full-stack engineer at https://www.hse24.de/

The Startup

Medium's largest active publication, followed by +610K people. Follow to join our community.

More From Medium

More from The Startup

More from The Startup

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade