Discovering Hooks in React: Building a Mini Pokédex with useState, useEffect, and a Custom Hook

Discovering Hooks in React: Building a Mini Pokédex with useState, useEffect, and a Custom Hook

February 22, 2026

In this article, I explain how Hooks have made functional components much more powerful by allowing them to manage state and side effects. I demonstrate the use of `useState` to create an interactive counter and `useEffect` to handle automated actions like a real-time clock. Finally, I share my method for creating a custom Hook (`useFetch`), which I used to build a dynamic mini-Pokedex with the PokeAPI.

Introduction to Hooks in React

In the last blog post, we explored components in React and how props allow us to pass data. Today, we'll delve into an important and very useful concept for managing state and effects in React applications: Hooks.

1. What is a Hook in React?

Hooks are functions that allow you to use state and other React features within functional components. Before their introduction in version 16.8, only class components could manage state. With Hooks, functional components have become more powerful and easier to write.

Here are some common Hooks:

  • useState: Allows you to manage local state within a component.

  • useEffect: Used to manage side effects (such as API calls or DOM updates).

  • useContext: Used to access a global context without passing props.

  • useRef: Allows direct access to a DOM element.

Today we'll focus on useState and useEffect with simple examples.

2. Using useState

useState allows you to add local state to a functional component. Here's a simple example:

jsx
1import React, { useState } from 'react';
2
3function Counter() {
4
5const [counter, setCounter] = useState(0);
6
7return (
8
9<div>
10<p>Counter value: {counter}</p>
11<button onClick={() => setCounter(counter + 1)}>Increment</button>
12
13</div>
14
15);
16
17}
18
19export default Counter;
20

In this example:

  • useState(0) initializes a counter state with the value 0.

  • setCounter is a function that updates the value of counter.

  • A button increments the counter with each click.

3. Using useEffect

useEffect allows you to execute code after the component has rendered. It is often used for API calls or updating the DOM.

Example:

jsx
1import React, { useState, useEffect } from 'react';
2
3function Clock() {
4
5const [time, setTime] = useState(new Date().toLocaleTimeString());
6
7useEffect(() => {
8
9const interval = setInterval(() => {
10
11setHeure(new Date().toLocaleTimeString());
12
13}, 1000);
14
15return () => clearInterval(interval);
16
17}, []);
18
19return <h2>It is {time}</h2>;
20
21}
22
23export default Clock;
24

Explanation:

  • useEffect creates an interval that updates the time every second.

  • The function returned by useEffect (clearInterval) is executed when the component is unmounted to prevent it from running indefinitely.

  • The [] in the second argument means the effect runs only once after the first render. We could add a state to listen for so the effect runs on every change.

4. Creating a Custom Hook: useFetch with PokeAPI

Custom hooks allow you to reuse specific logic while saving lines of code. We'll create a useFetch hook that retrieves data from an API and displays it.

In this example, we'll use PokeAPI to create a mini Pokédex.

Creating the useFetch.js Hook

jsx
1import { useState, useEffect } from 'react';
2
3function useFetch(url) {
4const [data, setData] = useState(null);
5
6const [loading, setLoading] = useState(true);
7
8const [error, setError] = useState(null); 
9
10useEffect(() => { 
11fetch(url) 
12.then((response) => response.json()) 
13.then((data) => { 
14setData(data); 
15setLoading(false); 
16}) 
17.catch((err) => { 
18setError(err); 
19setLoading(false); 
20}); 
21}, [url]); 
22
23return { data, loading, error };
24}
25
26export default useFetch;

Using the Hook in an App.js component

jsx
1import './App.css';
2import { PokemonDetails } from './components/PokemonDetails';
3import useFetch from './hooks/usefetch';
4import { useState } from 'react';
5
6function App() { 
7const [name, setName] = useState(''); 
8const { data } = useFetch('https://pokeapi.co/api/v2/pokemon/'+name); 
9
10return (
11
12<div className="App">
13
14<div className='pokedex-content'>
15
16{data && <PokemonDetails data={data} />}
17
18<form>
19
20<label>Pokémon number or name</label>
21
22<div className='input-group'>
23
24<input onChange={(e) => setNom(e.target.value.toLowerCase())} type='text' placeholder='Search for a Pokémon' />
25
26</div>
27
28</form>
29
30</div>
31
32</div>
33
34);
35
36}
37
38export default App;
39

What happens in PokemonDetails.js

jsx
1import React from 'react';
2
3export const PokemonDetails = ({ data }) => { 
4return( 
5<div className="pokemon-details"> 
6<div className="pokemonScreen"> 
7<img src={data.sprites.versions['generation-v']['black-white'].animated.front_default} alt={data.name} /> 
8<h3>{data.name.charAt(0).toUpperCase() + data.name.slice(1)}</h3> 
9</div> 
10</div> 
11);
12}

Preview

![Mini Pokedex Demo](https://gith(ub.com/ben4ali/upload-images/blob/main/Mini-Pokedex-Demo.gif.gif?raw=true)

Summary of what's happening

  1. The App component uses the custom useFetch hook to retrieve data for a Pokémon from the PokeAPI.

  2. useState is used to manage the name state, which represents the name or number of the Pokémon to search for.

  3. When a user types in the input field, the name state is updated with the lowercase value thanks to useState.

  4. The retrieved data is passed to the PokemonDetails component as props, as I demonstrated last week to display the Pokémon's details.

  5. The PokemonDetails component receives the Pokémon's data as a prop.

  6. It displays a GIF image of the Pokémon and its name formatted with the first letter capitalized.

  7. The details are displayed in a div with the class pokemon-details.

Additional Resources

If you have any difficulties, you can look at or clone my GitHub Repository to understand. You will find the complete source code and detailed instructions there.

Conclusion

Today, we learned about Hooks in React, focusing on useState and useEffect, and we saw how to create a custom Hook to simplify data retrieval. Hooks make functional components more powerful and reusable.

In the next blog post, we will explore routing with React Router to navigate between different pages in a React application.

Sources

Continue reading

More articles