Use React's useState and useEffect Hooks

Queen Nnakwue
author
Queen Nnakwue
Yellow shapes on a yellow background

If you've been working with React for a while, or you're a newbie, you will most likely attest to the fact that Hooks solve a wide variety of seemingly unconnected problems.

Before the release of React hooks in 2019, the only way to "attach" reusable behavior to a component was through traditional patterns like render props and higher-order components. Using these patterns requires you to redesign your components which were, by all means, unmanageable and made code difficult to decipher, especially when building large applications.

These issues led to the formation of hooks for sharing stateful logic. A component can change its state without changing its hierarchy, redesigning the component, or changing its structure. More so, this stateful logic can be extracted independently and reused across different components of your application. Hooks also let you use state and other React features without writing classes.

In this article, we will be introducing React hooks from the ground up. We will start by looking at hooks from a high level - what are they, and why you should use them. I'll also take a look at the useState, and useEffect hooks.

Prerequisites

A basic knowledge of React is required to get the full value out of this article.

What is a hook?

Hooks are functions that help you use state independently without writing a class. It is a new React feature that helps you write pure functional components without using the class syntax or this keyword.

Additionally, we can leverage hooks to combine React concepts like props, state, context, refs, and lifecycle in our application. Hooks provide a more direct API to these concepts.

It also lets us structure the logic inside a component into reusable entities.

Motivation Behind Hooks

Before the addition of hooks in React, developers encountered myriad problems ranging from difficulty reusing stateful logic between components to finding it hard to understand complex components. One of the motivations behind hooks is that they solve the problem of having to use layers of providers, consumers, higher-order components, render props, and other abstractions to reuse stateful logic between components in your application. Hooks gives us the liberty to have a logic that can stand alone in our component and repeatedly use without having to restructure your code. This invariably makes it easy to use hooks among many components in our application.

Another motivation behind the addition of hooks is that they solve the problem of maintaining large, cumbersome applications. For example, a component might affect some data fetching in componentDidMount and componentDidUpdate. The componentDidMount method might also contain some varying logic that sets up event listeners. This is where the problem lies. Jointly related code gets split apart, while completely unrelated/varying code ends up joining in a single method, making it too cumbersome and easy to introduce bugs.

How do hooks fix this issue, you may ask? Kindly follow along. Hooks allow you to divide a component into individual functions based on related pieces such as fetching data, rather than forcing a divide based on lifecycle methods (componentDidMount/componentDidUpdate).

Using the State and Effect hooks in React

Lets take a deep dive into these two hooks to fully understand them. I'll show you how you can effectively use both hooks with examples. Sounds interesting? Let's get started.

We will be starting with the most important React hook- **useState**. To get started, let's create a new react application. In your terminal, run npx create-react-app to create all the boilerplate you need for your react application. Inside your App.js file, create an App functional component with a - and a + button with a span in the middle, which displays our count like so:

import React from 'react';
export default function App(){
return(
<>
<button>-</button>
<span>0</span>
<button>+</button>
</>
)
}

This is a simple react application with no functionalities at all, and we are going to be adding the counter functionalities by using the useState hook. To get started with implementing these functionalities, the first thing we'll need to do is import the hook we will use. Now, inside your App.js, at the top, import useState from React.

Before we start, let me quickly iterate on the rules of hooks, one of which is that hooks can only be used inside of a function component. You cannot use them inside of a class component because classes have their way of doing the same things that hooks do.

Another point to note about Hooks is that you cannot put hooks inside of conditional statements, functions, loops, and they cannot be nested in anything. They must be at the top level of your function, and nothing should be around them. Now that we know the rules let's talk about the useState hook and how it differs from the class state.

useState

To use the useState hook, all we need to do is just call the useState, which is a function. The thing that we pass into useState will be what our default state is, which in our example above is going to be 4. useState always returns an array with two values. The first value will be your state, which In our example, will be count, and as a second value, we will use the setCount function to which we will use to update our state. Let's update our application. In between your span element, replace the 0 with {count} so it can be rendered. Your App.js file should look like this:

import React, { useState } from 'react';
export default function App(){
const [ count, setCount] = useState(4);
return(
<>
<button>-</button>
<span>{count}</span>
<button>+</button>
</>
)
}

The next thing I want to talk about is how we can actually setCount. To do that, lets set an onClick called decrementCount inside our - button. Following that, let’s define a function called decrementCount like so:

function decrementCount(){
setCount(preCount => preCount - 1)
}

Let’s also apply same functionality inside our + button like so:

function incrementCount(){
setCount(preCount => preCount + 1)
}

Run npm start and click on both buttons to see how well they perform. Awesome right? These are the basic functionalities of the useState hook. Your App.js file should look like this:

import React, { useState } from 'react';
export default function App(){
const [ count, setCount] = useState(4);
function decrementCount(){
setCount(preCount => preCount - 1)
}
function incrementCount(){
setCount(preCount => preCount + 1)
}
return(
<>
<button onClick={decrementCount}>-</button>
<span>{count}</span>
<button onClick={incrementCount}>+</button>
</>
)
}

useEffect

Lastly, let's talk about the useEffect hook. Two things you should note about the useEffect hook. Firstly, it lets you perform side effect in functional component and secondly, the useEffect hook is synonymous in function to componentDidMount, componentDidUpdate and componentWillUnmount.

First things first, to make use of the useEffect hook, you have to import it from React and call it at the top of your page, similar to the useState. Let's begin: In your editor, type the following piece of code.

import { useEffect } from "react";
function App(){
return(
<div className="App">Learning useEffect</div>
)
}

From the above, we rendered “Learning useEffect” on our code and when it is rendered, the useEffect hook will be called. Add a useEffect Inside of our function App like so:

import { useEffect, useState } from "react";
function App(){
const [counter, setCounter] = useState(0);
useEffect(() =>{
})
return(
<div className="App">useEffect</div>
)
}

Inside the parenthesis, we can pass a function, which can be whatever logic we want in our code. However, it is important to understand that the useEffect will get called after our page is rendered. From our code above, whenever our state changes, the useEffect will be called. The state has a default value of 0, and whenever the default value changes, useEffect will be re-rendered. For example, in our application, let's console.log counter and add a button with an onClick function to increase our counter value by 1 whenever the button gets clicked.

import { useEffect, useState } from "react";
function App(){
const [counter, setCounter] = useState(0);
useEffect(() =>{
console.log(counter)
})
return(
<div className="App">
{counter} <button onClick={() =>{
setCounter(counter + 1)
}}>Increase</button>
</div>
)
}

Rules of Hooks

  • Call hooks at the top level: As a rule of thumb in React, hooks should only get called at the top level of your React application before any early returns. It must not get called inside loops, conditions, or nested ****functions.
  • Hooks must be called from React functions components or custom hooks only, not JavaScript functions

If some things didn't quite make a lot of sense to you, check out the [hooks API reference] (https://reactjs.org/docs/hooks-reference.html), or https://reactjs.org/docs/hooks-faq.html