Understanding React hooks
Tags: react, webdev, javascript
Published: 2023-02-22 00:15:43

by [Solisoma Madubueze](https://blog.openreplay.com/authors/solisoma-madubueze)

[`React`](https://reactjs.org/) is one of, if not the most well-liked [`JavaScript`](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript) frameworks. An attribute called Hooks is part of `React`. Due to their complexity, `React` hooks might be confusing for beginners, who thus become stuck when they encounter them. In this article, we will discuss that.

## What are React hooks?

`React` hooks are `JavaScript` functions that isolate the reusable part from a functional component.
Hooks are `React` [`APIs`](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction) added to `React` 16.8. They made it possible for features previously only used in `React` class components to come into `React` functional components. They are functions that bring the power of `React` class components to functional components. Hooks allow us to separate our code, manage side effects, and more.

## Origin of React hooks

`React` functional and class components had different purposes before hooks. The only time functional components were utilized was to render data to the user interface (UI). Only parent components, which were class, could receive and render `props` for them. Functional components were unaware of the lifecycle and did not maintain an internal state.

Contrarily, class components keep track of a component's internal state and provide lifecycle methods that let you do activities during each stage. For instance, after a component mounts, you can update the state due to user interaction and fetch data from an external `API`. A class component keeps track of its internal state and lifetime, making all of this feasible. The term "smart components" was used to describe class components and is still used today.

`Hooks` were added to solve some of the problems related to using `React` class components, but some are not directly connected to `React` but, rather, the way native `JavaScript` classes are designed.

React hooks have a few rules, including:

- Hooks can only be called inside React function components.
- Hooks can only be called at the top level of a component.
- Hooks cannot be conditional

These rules are crucial; breaking them could make your hooks stop working.

## Types of React hook
- [useState](https://beta.reactjs.org/reference/react/useState)
- [useEffect](https://beta.reactjs.org/reference/react/useEffect)
- [useCallback](https://beta.reactjs.org/reference/react/useCallback)
- [useMemo](https://beta.reactjs.org/reference/react/useMemo)
- [useContext](https://beta.reactjs.org/reference/react/useContext)
- [useRef](https://beta.reactjs.org/reference/react/useRef)
- [useReducer](https://beta.reactjs.org/reference/react/useReducer)
- [useId](https://beta.reactjs.org/reference/react/useId)
- [useImperativeHandle](https://beta.reactjs.org/reference/react/useImperativeHandle)
- [useDebugValue](https://beta.reactjs.org/reference/react/useDebugValue)
- [useDeferredValue](https://beta.reactjs.org/reference/react/useDeferredValue)
- [useInsertionEffect](https://beta.reactjs.org/reference/react/useInsertionEffect)
- [useLayoutEffect](https://beta.reactjs.org/reference/react/useLayoutEffect)
- [useSyncExternalStore](https://beta.reactjs.org/reference/react/useSyncExternalStore)
- [useTransition](https://beta.reactjs.org/reference/react/useTransition)

Above are the types of `React` hooks we have, but we will be digesting the first four (4) out of the fifteen we have listed because those are the ones we are likely to use when working on a project.

## useState

In some projects (websites, web apps, etc.), we need them to behave differently when the user inputs different values or opt-in for different options. `useState` allows us to achieve that.

The `React` `useState` hook lets us keep track of the state while using the function component.

"State," according to Oxford Languages, is the particular condition someone or something is in at a specific time. In `React`, state refers to the value of a component's property at a specific time. 


By using `useState,` we know when these values have changed from their initial state to another, and we can update our components according to those changes.

Let's write some code to implement the `useState` using a functional component named `myFavouriteFood`.

```javascript
import { useState } from "react";

function myFavouriteFood() {
  const [food, setFood] = useState("fried rice");

  return <h1> My favorite Food is {food}!</h1>;
}
```
We first imported the `useState` into our [module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) in the code above because we cannot use it unless we first import it into our module. `useState` is defined before the `return` keyword; this is to allow them to initialize before the function returns any value, as we can see in our code. We initialize our `useState` at line 4 before returning a value at line 6. Some of us might need clarification about what we did in line 4. We [destructured](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#:~:text=The%20destructuring%20assignment%20syntax%20is,from%20objects%2C%20into%20distinct%20variables.) the `useState` to get the `return` value. The `useState` function returns a list with two values as its output. The first value is the actual state we will be using, while the second is a function we will use to update this state. By destructuring them, we now get their values. The first value is assigned to the variable food, while the second is assigned to the variable setFood.

### Updating our state

How do we update the value of food based on the user's activity on the web app? To explain this, let's say we have the multiple choice option and want to return different food as the user's favorite when they choose one out of the multiple choices we provided.

Let's update our code to add multiple choices.

```javascript
import { useState } from "react";

function myFavouriteFood() {
  const [food, setFood] = useState("");
  const updateFood = (e) => setFood(e.target.value);

  return (
    <>
      <h1> Select your favourite food </h1>
      <input
        type="radio"
        id="Fried rice"
        name="fav food"
        onClick={updateFood}
        value="Fried rice"
      />
      <label for="Fried rice">Fried rice</label>
      <br />
      <input
        type="radio"
        id="Jollof rice"
        name="fav food"
        onClick={updateFood}
        value="Jollof rice"
      />
      <label for="Jollof rice">Jollof rice</label>
      <br />
      <input
        type="radio"
        id="fufu"
        name="fav food"
        onClick={updateFood}
        value="Fufu and Egusi soup"
      />
      <label for="fufu">Fufu and Egusi soup</label>
      <br />
      <p> My favorite Food is {food}!</p>
    </>
  );
}
```

In our code, we updated the value of food when the user clicked on a particular option using events. We achieved this by passing a [callback function](https://developer.mozilla.org/en-US/docs/Glossary/Callback_function) to the `onClick` property. Inside the callback function, the `updateFood` function, we updated the variable food by calling the `setFood` function and passing the value of the option the user clicked as an argument. Take note that the second value that `useState` returns, which is `setFood` in our case, takes in one argument: the updated value of our state. To understand more about `JavaScript` events, try reading this article [All About JavaScript Events](https://blog.openreplay.com/all-about-javascript-events/). 

Although updating strings, integers, and boolean in `useState` is simple, updating objects and arrays in `useState` can be difficult due to how they behave. In `React`, we are not allowed to mutate the values inside the `useState`. What I'm trying to say is that the values that `useState` holds shouldn't be modified; instead, when `useState` is updated, the values that are supplied to it should point to a new object, as is the default behavior of integer, string, and boolean. As a result, they are easier to update than arrays and objects in `useState`. Updating objects and arrays in `useState`, we must create a duplicate or new value that points to a new object.

### Updating arrays in State

We use the spread method `...` to update arrays in the state. Depending on what we want to accomplish, we can also utilize the concat, map, filter, and slice methods. We use these methods to update arrays in the state since they return an array pointing to a new object. But in this instance, we'll employ the spread strategy.

```javascript
import { useState } from "react";

function myFavouriteFood() {
  // Array as the initial value of useState
  const [foodClicked, setFoodClicked] = useState([]);

  const updateFood = (e) => {
    // Updating arrays
    const newFoodClicked = [...foodClicked, e.target.value];
    setFoodClicked(newFoodClicked);
  };

  return (
    <>
      <h1> Select your favourite food </h1>
      <input
        type="radio"
        id="FR"
        name="fav food"
        onClick={updateFood}
        value="Fried rice"
      />
      <label for="FR">Fried rice</label>
      <br />
      <input
        type="radio"
        id="JR"
        name="fav food"
        onClick={updateFood}
        value="Jollof rice"
      />
      <label for="JR">Jollof rice</label>
      <br />
      <input
        type="radio"
        id="fufu"
        name="fav food"
        onClick={updateFood}
        value="Fufu and Egusi soup"
      />
      <label for="fufu">Fufu and Egusi soup</label>
      <br />
      <hr />
      <p> The list of Foods you have clicked are!</p>
      {foodClicked.map((item) => (
        <p>{item}</p>
      ))}
    </>
  );
}
```
Try running this code and see the output. You are expected to see the foods you have clicked.

### Updating objects in State

The spread method `...` is used to update objects in State. The concat, map, and other methods we have stated in the array are not applicable because objects don't support them.

```javascript
import { useState } from "react";

function myFavouriteFood() {
  // Object as the initial value of useState
  const [foodData, setFoodData] = useState({
    "Fried rice": 0,
    "Jollof rice": 0,
    "Fufu and Egusi soup": 0,
  });
  const updateFood = (e) => {
    // Updating objects
    foodData[e.target.value]++;
    setFoodData({ ...foodData });
  };

  return (
    <>
      <h1> Select your favourite food </h1>
      <input
        type="radio"
        id="FR"
        name="fav food"
        onClick={updateFood}
        value="Fried rice"
      />
      <label for="FR">Fried rice</label>
      <br />
      <input
        type="radio"
        id="JR"
        name="fav food"
        onClick={updateFood}
        value="Jollof rice"
      />
      <label for="JR">Jollof rice</label>
      <br />
      <input
        type="radio"
        id="fufu"
        name="fav food"
        onClick={updateFood}
        value="Fufu and Egusi soup"
      />
      <label for="fufu">Fufu and Egusi soup</label>
      <br />
      <hr />
      <p>
        {" "}
        Foods and times you have clicked them:{" "}
        {Object.keys(foodData).map((item) => (
          <p>{`${item}: ${foodData[item]}`}</p>
        ))}
      </p>
    </>
  );
}
```
Try running this code and see the output. You are expected to see the foods you have clicked and the number of times you have clicked them.




<h2>Session Replay for Developers</h2> 
<p><em>
Uncover frustrations, understand bugs and fix slowdowns like never before with <strong><a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a></strong> — an open-source session replay suite for developers. It can be <strong>self-hosted</strong> in minutes, giving you complete control over your customer data
</em></p>
<img alt="OpenReplay" width="768" height="400" src="https://blog.openreplay.com/assets/overview_Z17Qdyg.png" class="astro-UXNKDZ4E" loading="lazy" decoding="async">
<em>Happy debugging! <a href="https://openreplay.com" target="_blank">Try using OpenReplay today.</a></em>





## useEffect

As its name suggests, the `useEffect` hook allows you to perform side effects in your components. It enables you to synchronize a component with an external system. In this scenario, external systems are those systems that are not managed by `React`, such as some browser APIs or third-party libraries.

How `useEffect` is triggered in `React` depends on its dependencies array.`useEffect` accepts two arguments. The second argument is optional.

```javascript
useEffect(<function>, <dependency array>)
// second argument is optional.
```
The first argument passed to the `useEffect` function is a callback function, and the second is an array popularly called a dependency array. A dependency array contains the values that your first argument (function) depends on. To use `useEffect`, we need to import it into our module and initialize it.

```javascript
import { useEffect, useState } from "react";
import fetchPost from "./post";

function PostDetails() {
  const [post, setPost] = useState([]);

  useEffect(() => {
    const get_post = fetchPost({ details });
    setPost(get_post);
  });
}
```

Our `useEffect` runs after our components are rendered. When our component is rendered, the post is fetched from the `API,` and we update the post variable (state) with its value when it returns a value. If we run this code, we will figure out that the `useEffect` is triggered continuously without stopping, making our component keep re-rendering. We might not notice that our component is being re-rendered because it shows the same content. But we can see the browser continuously fetching the post when we move to the network tab after right-clicking and clicking on inspect.

To prevent this, we need to add the dependency array. As I said, how `useEffect` is triggered in `React` depends on its dependency array. The dependency array tells `React` either to re-run a `useEffect` or not. The dependency array can be filled, empty, or not specified, and the state it is in makes it behave differently. How does this work? 

### Filled
If a dependency array is specified or filled, `React` re-runs the `useEffect` whenever any of the values inside the dependency array changes.

```javascript
import { useEffect, useState } from "react";
import fetchPost from "./post";

function PostDetails() {
  const [post, setPost] = useState([]);
  const [clicked, setClicked] = useState(false);

  useEffect(() => {
    const get_post = fetchPost({ details });
    setPost(get_post);
  }, [clicked]); // Filled array.
}
```
When the value clicked is changed, `React` re-run the `useEffect` and re-renders the component.

### Empty

This is when we provide the dependency array without adding any value inside the array. This tells `React` to run the `useEffect` when the component is rendered for the first time only. The `useEffect` runs only ones which are when the component renders the first time.

```javascript
import { useEffect, useState } from "react";
import fetchPost from "./post";

function PostDetails() {
  const [post, setPost] = useState([]);

  useEffect(() => {
    const get_post = fetchPost({ details });
    setPost(get_post);
  }, []); // Empty array.
}
```
### Not specified

This is when the dependency array is not specified at all. It tells `React` to re-run the `useEffect` whenever the component re-renders.

```javascript
import { useEffect, useState } from "react";
import fetchPost from "./post";

function PostDetails() {
  const [post, setPost] = useState([]);

  useEffect(() => {
    const get_post = fetchPost({ details });
    setPost(get_post);
  }); // No array.
}
```
`React` will continue to re-run this `useEffect` whenever the component re-renders. If you are not careful when using your `useEffect` this way, you might end up defining a `useEffect` that keeps re-running. How I address this issue is by setting a condition the function inside the `useEffect` must pass before it can run.

## useCallback

The `React` `useCallback` Hook returns a memoized callback function.

Memoization, according to Wikipedia In computing, is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the [cached](https://en.wikipedia.org/wiki/Cache_(computing)) result when the same inputs occur again. This is what the `React` `useCallback` hook does, but instead of caching the value, the `useCallback` hook caches the function itself. `React` when re-rendering a component recreates all of its functions. This automatically decreases performance. `useCallback` addresses this issue by telling `React` whether to recreate its function or not when re-rendering a component.

This allows us to isolate resource-intensive functions so that they will not automatically run on every render. `useCallback` accepts two arguments, just like `useEffect`; the first is a function, while the second is an array known as a dependency array.

```javascript
useCallback(<function>, <dependency array>)
```

The `useCallback` hook only runs when one of its dependencies updates.

```javascript
import { useState, useCallback } from "react";

function App() {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

  const increment = () => {
    setCount((c) => (c += 1));
  };

  const addTodo = useCallback(() => {
    setTodos((t) => [...t, "New Todo"]);
  }, [todos]);

  return (
    <div>
      <p> Todos {todos} </p>
      <p> Count: {count}</p>
      <button style={{ marginRight: "20px" }} onClick={addTodo}>
        {" "}
        add Todo
      </button>
      <button onClick={increment}>+</button>
    </div>
  );
}
```

When we click the `+` button, the `useCallback` doesn't run because its dependency `todos` was not changed. The `useCallback` will run when we click on the add Todo button, which updates the `todos` state.

## useMemo

The `React` `useMemo` Hook returns a memoized value.

The `useMemo` hook is quite similar to the `useCallback` hook; however, instead of caching functions as in the case of `useCallback`, we cache and return the outcome of an expensive calculation in `useMemo`.

You can prevent expensive, resource-intensive functions from running unnecessarily by using the `useMemo` Hook. Like `useCallback`, `useMemo` also takes two arguments: the first is a function, and the second is an array called a dependency array.

```javascript
useMemo(<function>, <dependency array>)
```

Defining an expensive function inside a component will decrease the performance of the component.

```javascript
import { useState, useCallback } from "react";

function App() {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

  const increment = () => {
    setCount((c) => (c += 1));
  };

  function expensiveCalculation(int) {
    for (let i = 0; i < 1000000000; i++) {
      int += 1;
    }
    return int;
  }

  const calculate = expensiveCalculation(count);

  const addTodo = useCallback(() => {
    setTodos((t) => [...t, "New Todo"]);
  }, [todos]);

  return (
    <div>
      <p> Todos {todos} </p>
      <p> Count: {count}</p>
      <button style={{ marginRight: "20px" }} onClick={addTodo}>
        {" "}
        add Todo
      </button>
      <button onClick={increment}>+</button>
      <hr />
      <p>Expensive calculation</p>
      <span>{calculate}</span>
    </div>
  );
}
```
It will take some time for the component to update when we run this code and hit the add Todo or `+` buttons. This demonstrates how this expensive function keeps executing during every re-render, lowering the component's performance.

However, applying `useMemo` will prevent our component from acting this way.

```javascript
import { useState, useMemo, useCallback } from "react";

function App() {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

  const increment = () => {
    setCount((c) => (c += 1));
  };

  function expensiveCalculation(int) {
    for (let i = 0; i < 1000000000; i++) {
      int += 1;
    }
    return int;
  }

  const calculate = useMemo(() => expensiveCalculation(count), [count]);

  const addTodo = useCallback(() => {
    setTodos((t) => [...t, "New Todo"]);
  }, [todos]);

  return (
    <div>
      <p> Todos {todos} </p>
      <p> Count: {count}</p>
      <button style={{ marginRight: "20px" }} onClick={addTodo}>
        {" "}
        add Todo
      </button>
      <button onClick={increment}>+</button>
      <hr />
      <p>Expensive calculation</p>
      <span>{calculate}</span>
    </div>
  );
}
```

This time, when we run this code, clicking the `+` button causes our component to update gradually, but clicking the `add Todo` button causes it to update instantly. This is so because, like `useCallback`, the `useMemo` hook only executes when one of its dependencies changes, in this case, only when the `+` button is clicked to update the count variable.



## Conclusion

We understand that `React` hooks are simply `JavaScript` functions. It allows us to implement some functionality that was only in the `React` class components in the `React` functional components. We also saw that the `useEffect` hook's re-rendering depends on its dependency array, `useCallback` and `useMemo` hooks will only run when any value in their dependency array changes, and `useState` helps us keep track of our component state.





[![newsletter](https://blog.openreplay.com/newsletter_Z1P0UIP.png)](https://newsletter.openreplay.com/)