Using React Hooks and useEffect() for a Pokemon Battle with Ash, Misty, and Brock

11. Hooks – Reusability, Readability, and a Different Mental Model

This chapter will introduce you to React Hooks, enabling you to avoid wrapping your components in classes just to gain access to the state of a component. Using fewer abstractions will make the components lighter and will enhance the readability of the code. You will be able to optimize code while using Hooks in components efficiently. You will be able to create abstractions with Hooks that can be reused and so we do not need to rely on class-based components or component life cycle methods.


In the previous chapters, we have seen how React handles state in class components. By the end of 2018, however, React developers had come up with a completely new API called Hooks, which changes how we manipulate the state of a component. This brings in massive syntax changes within the React framework. Even more importantly, this new method of state management can be used to manipulate state of the functional components.
Nothing in the life of a React component has a more significant effect than Hooks, which, of course, begs the question: what problems do Hooks solve that the former APIs could not? Previously, if we wanted to declare a state, we had to create a whole class and all the boilerplate code for that. Hooks, on the other hand, enable you to declare the state of a component with just one line. Hooks make React code more readable, maintainable, and reusable, while also making it a lot easier for newcomers to understand.
The Hooks library has been built with a newer version of ECMAScript; a script used to package JavaScript code for reuse. In this chapter, we will first take a look at the functionalities of Hooks. Later on in this chapter, we will look at the old style of writing code using class-based components and render props in React components and compare this method directly with Hooks and see how Hooks can improve the code you write.
Let's get started to see how you, as a developer, can benefit from embracing hooks.


In this section, we are going to introduce two of the popularly used React hooks: useState and useEffect. These are widely used and can solve most of our problems. The useState hook is used to initialize the state of a component and get access to a function that allows you to modify the state of that same component. The useEffect hook, on the other hand, is used when changes are made to the component, similar to the use case for componentDidMount or componentDidUpdate methods in class-based components.
There are other types of hooks that come bundled with the React library. You can find a complete list of these at .
Let's dive right into these two particular hooks in more detail.


useState is the first type of hook that we are going to use. It gives us all the functionality that this.state and this.setState provide for class-based components. When we call useState, it will return an array where the first item in the array is the initial state of the component (which is what we pass in React.useState), and the second item is a function that acts identically as setState in a class-based component.
We can declare useState as following:
const [state, setState] = React.useState({ someFlag: false });// or like thisconst result = React.useState({ someFlag: false });const state = result[0];const setState = result[1];Copy
The square brackets might seem intimidating, but they are exactly like object destructuring in JavaScript, except here we use arrays.
Look at JavaScript de-structuring here: .
We have also discussed object de-structuring in Chapter 7, Communication between Components.
The first element of the arrays is the state itself, while the second element is a function that updates the state and, of course, triggers a re-render. We call this the setter function.
It can have two signatures; we can also say that the setter function can be overloaded. We will discuss the overloading of the setter function in more detail in Chapter 12, State Management with Hooks.
In this case, we will use the following code:
setState({ someNewState: true });setState(prevState => ({ someNewState: !prevState.someNewState }));Copy
The first example just takes a new state. For the second, you pass in a function with the previous state as the argument, and that function must return the new state. This is useful when our new state depends on the previous state. We will see the implementation shortly.
This behaves exactly like this.setState in class components. Now, let's work through a hands-on exercise to rend
er an image using the useState hook.

Exercise 11.01: Displaying an Image with the Toggle Button

In this exercise, we will display an image in a functional component. We will use an <img/> tag to render an image. Image tags require at least the source properties src and alt for accessibility. We will create a base component, and this will be provided to <Base/> and passed down as props later. To do so, let's go through the following steps:
Start by creating a new React project, which we will call imagehook, start the project, and take a look at the browser window that should have opened for you automatically:
$ npx create-react-app imagehook
$ cd imagehook
$ yarn start
Delete src/logo.svg. We won't be using this file, so we don't need to include it.
Replace the contents of src/App.css with the following:
img {
width: 200px;
body {
margin: 20px;
button {
width: 200px;
height: 50px;
background: #4444ff;
color: white;
font-weight: bold;
border: none;
cursor: pointer;
You'll want to find an image to display in our component. For example, we could grab a nice picture of coffee beans from Unsplash, like the image we will use in this example: .
(Photo by Nadia Valko on Unsplash:
Replace the contents of the App component with the functional component below. This will set up our base UI, which we will refine through hooks later:
import React from "react";
import "./App.css";
const App = () => {
const url = "";
return (
<div className="App">
<img src={url} alt="Some coffee beans" />
<br />
<button>Toggle Image Display</button>
export default App;
This should give us our starting component UI, matching the following screenshot:
Figure 11.1: Toggle button
Figure 11.1: Toggle button
Let's expand this functional component a little more by making the image display toggleable and dependent on a displayImage Boolean value.
First, add the displayImage Boolean with a default value, false, and then change the JSX containing the <img> tag to be conditionally rendered when displayImage is true:
const App = () => {
const url = "";
const displayImage = false;
return (
<div className="App">
{displayImage && <img src={url} alt="Some coffee beans" />}
<br />
<button>Toggle Image Display</button>
We are now ready to start adding React Hooks to this component. We will add a new line to the component that calls React.useState, pass in an initial value, false, and de-structure the result of that call into two new variables: displayImage and setState.
Use the following code
const [displayImage, setState] = React.useState(false);
Note that we are not using setState yet; we will be doing that soon. When your browser refreshes, you should no longer see the image on your component.
Next, we will need to implement a function that will toggle the displayImage flag via our setState function:
const toggleImage = () => setState(!displayImage);
Finally, hook it up by adding the toggleImage call to the button's onClick handler:
<button onClick={toggleImage}>Toggle Image Display</button>
Our final component code in src/App.js should now be the following:
1 import React from "react";2 import "./App.css";3 4 const App = () => {5 const url = "";6 const [displayImage, setState] = React.useState(false);7 const toggleImage = () => setState(!displayImage);8 return (Copy
The complete code can be found at: .
The output is as follows:
Figure 11.2: Final output of the Toggle button
Figure 11.2: Final output of the Toggle button
Now, what would previously have been a complex abstraction has been reduced to only a function call. We don't need a complex constructor, multiple additional state modifying functions, or any other additional logic. It is close to our view layer; the order reads from top to bottom, which makes it super readable. Our JSX remained the same and no more wrappers got injected into the React tree. Similar to how we moved state modification away from class components, let's now see how we can move away from life cycle methods used in class components and use the useEffect hook instead.

useEffect – from Life Cycle Methods to Effect Hooks

Hooks not only encompass new syntax in React but also require a different design pattern when it comes to developing the functional components in a React application. During the development cycle of a React application, components are continuously created, modified, and destroyed. Developers might want to use these events to call an API to modify the DOM elements, or maybe keep a log of information to display in the console.
As we've discussed previously, class components have life cycle methods to do this. If we wanted to do something like modifying the DOM or fetch some data by initiating a network request, we would use the life cycle methods, componentDidMount, componentDidUpdate, or componentWillUnmount. These life cycle events are tied to the insertion, updating, and removal of a given component. If you want to attach an event listener to a button in a form component, you could do that in componentDidMount. If you eventually need to remove it, you will use the componentWillUnmount method.
Other frameworks, such as Vue.js or Angular, have the concept of using life cycle methods as event callbacks. They provide callbacks to create a way to respond to events such as mouse clicks or mouse scrolls. However, with Hooks, there is a massive fundamental shift in the usual mental model. Instead of putting the code separately in each life cycle method, we group our logic and put it together into a functional hook called Effects.
Let's look at an example. We will create a class component, Comp, within which we will display our name prop when the component updates on mount. We will do this by implementing the life cycle methods, componentDidUpate and componentDidMount, as mentioned in Chapter 4, React Lifecycle Methods, as follows:
class Comp extends React.Component { componentDidMount(){ console.log(; } componentDidUpdate(prevProps){ if( !== { console.log(; } } render() { return <div>{}</div>; }}Copy
If we want to capture similar functionality in a functional component as provided by these life cycle methods in a class component, we will need to use the useEffect hook. With the useEffect hook, we are going to take a different approach in terms of syntax. We will rewrite the Comp component, where we will create the logic first and will control when to run it like the following code:
const Comp = props => { React.useEffect(() => { console.log("name prop changed");}, []);return <div>{}</div>;}Copy
As you can see from the preceding code, the useEffect hook takes two arguments:
the first is the function that will be used to handle the effect.
the other argument is an array of variables which will be used to determine whether we should call the function we passed in as the first argument.
In the preceding example, we have a React Effect we want to use, but we only want it to be executed when the name attribute in props gets updated, so we pass in [] as our second argument. This effect (the first callback argument) will rerun only if the name prop changes. The logic is now encapsulated.
In a useEffect hook, the first argument is always a function where we put what we want to do (what we would have put into our life cycles for class-based components), and the second is an array of values. In that array, we set out our conditions when to perform effects. We don't need to rely on updates, mounts, and removals; we can create our own conditions. We can add multiple values to that array, which means that React will run that effect any time any of these values change. We can also leave this empty; in that case, the effect only runs on mount. We can also omit that array entirely in which case it will run every time the component re-renders.
The biggest difference between life cycle methods and useEffect is that with life cycle methods, you must think about which event is the right event to listen to and implement the correct logic for each. With useEffect, we think about the logic first and then control when to run it.
This has a few implications in terms of the readability of our code. For one, life cycle methods can be cluttered. If we have multiple things to do (such as logging the output and a network request), they will live inside the same function; they cannot be extracted.
In the following code, we are creating a class component, Comp, where we will perform multiple different actions when the component updates; the name prop will be displayed in the console and a network request will be initiated:
class Comp extends React.Component { componentDidMount(){ console.log( } componentDidUpdate(prevProps){ // this is one piece of logic if( !== { console.log(; } // this is another fetch(''); }}Copy
In the preceding example, the fetch method used to initiate a network request has no connection with the console.log function, yet it still lives inside the same componentDidUpdate life cycle method in a class-based component.
useEffect focuses on the logic and allows you to couple logic with specific properties or attributes. This allows us to create one effect for the console and a different one for a network request, and we can control when they are called. This provides a cleaner and more elegant approach to writing different effects for different use cases.
Using useEffect hooks, we would rewrite the Comp component to look more like this:
const Comp = props => { React.useEffect(() => { console.log("name prop changed");}, []);React.useEffect(() => { fetch('');}, []);return <div>{}</div>;}Copy
re, there are two separate hooks for the two different actions where the logic remains encapsulated. Our code is cleaner and the logic for each property is clear and easy to follow. Using this knowledge, let's build a component using useEffect.

Exercise 11.02: Creating a Login State Using useEffect

In this exercise, we will utilize useEffect to create a component where we simulate logging in (and remaining logged in even if we refresh the page) through a combination of hooks and localStorage.
localStorage is a part of the HTML5 specifications. With the help of localStorage, we can write values to our browser that will be persistent across re-renders. This constitutes unique persistent storage for our domain. If you would like to know more about localStorage, you can visit MDN for more information: ).
For this exercise, it is recommended to have Chrome developer panels open on the Application page. For that, you only need to right-click on your web page, click on inspect, and, on the tabs starting with elements, find Application -> Storage -> Local Storage:
Begin by creating a new React project, which we will call login-storage, start the project, and take a look at the browser window that should have opened for you automatically:
$ npx create-react-app login-storage
$ cd login-storage
$ yarn start
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
) instead.