# React Hooks: useState Explained

## Introduction

State management is a crucial aspect of building React applications. In React, state refers to any data that the application needs to keep track of and update over time. For example, a user's name, email, and contents of shopping carts are all examples of state.

The `useState()` is a built-in hook that allows developers to declare and manage state variables in function components.

In this article, we will explore the basics of `useState()`, best practices and some common pitfalls.

## Setting up `useState()`

Let's see how to set up the `useState()` before we can use it for state management.

Here are the steps to do so:

* Import `useState` from 'react':
    
    ```javascript
    import { useState } from 'react';
    ```
    
* Declare a state variable:
    

```javascript
const [stateValue, setStateValue] = useState(initialValue);
const [name, setName] = useState("Jhon");
```

Here, `stateValue` is the current state value, `setStateValue` is a function to update the state value, and `initalValue` represents the initial value that we can set to a valid javascript type: a boolean, string or object.

The `useState()` returns an array of exactly two elements:

1. **state value:** This represents the current state value.
    
2. **set function**: This allows us to update the state value and trigger a re-render.
    

It is a convention to name the state variables like `[something, setSomething].`

## **Updating State with** `useState()`

Once we've set up `useSate` in our component, we can use it to manage state values.

Here's an example of how to use `useState()`\[something, setSomething\]. to update a counter value in response to clicking a button.

```javascript
import { useState } from 'react'; // import useState[something, setSomething].

function Counter() {
  const [count, setCount] = useState(0); // declare counter state

  function handleClick() {
    setCount(count + 1); // update counter value.
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}
```

In the above example, we declare a `count` state variable, with an initial value of `0`, and a state update function called `setCount`. In the `handleClick` function, we use `setCount` to update the `count` value by adding `1`.

When the increment button is clicked, the `handleClick` updates the `count` value using `setCount`, and when the state updates, React triggers a re-render of the component to reflect new state values.

> Keep in mind that every time we update a state variable, React automatically re-renders the component.

## Caveats when updating a state

When updating state variables using the `set` function, there are some caveats we should be aware of to avoid unexpected behaviour.

### The updated state is not available in the currently executed code block

When you call the `set` functions to update the state variable, the state is not immediately updated within the currently executing code block. This means that if you access the state variable immediately after calling the `set`, you will still get the previous value of the state.

For example, consider the following code:

Suppose the count value is 0.

```javascript
function handleClick() {
  // initial count value is 0
  setCount(count + 1); // increment count
  console.log(count); // Still 0
}
```

In the example, when the `handleClick` function executes, it calls `setCount()` to update the `count` state variable, and then immediately logs the value of the `count` to the console.

However, the output of the `console.log()` statement will still be 0, even though we just called `setCount()` to update the `count` value. This is because the new value of `count` is not immediately available within the `handleClick` function.

Instead, React put updates into a `queue`, and trigger a re-render. During the re-rendering phase, React process updates from the `queue` and reflects the updated states into UI.

### Batch update

* In cases when we need to update more than one state variable, React groups multiple state update operations into a single update operation, and this process is called `batch update`.
    
* The `batch update` improves performance by reducing the number of re-rendering.
    

Suppose the `count` value is 2. The following `handleClick` function calls setCount three times in a row, each time incrementing the count value by one.

```javascript
function handleClick() {
  setCount(count + 1); // setCount(2 + 1)
  setCount(count + 1); // setCount(2 + 1)
  setCount(count + 1); // setCount(2 + 1)
}
```

However, React will not update the state immediately nor does it trigger a re-renders for each call to `setCount()`. Instead, it groups state updates and performs a single re-render with the updated state value.

To avoid this issue, we can pass a function to the `setCount()` instead of a value. This function will receive the previous state value as an argument and return a new state value.

```javascript
function handleClick() {
  setCount(prevCount => prevCount + 1); // setCount(2 => 2+1)
  setCount(prevCount => prevCount + 1); // setCount(3 => 3+1)
  setCount(prevCount => prevCount + 1); // setCount(4 => 4+1)
}
```

Here, `prevCount => prevCount+1` is called the updater function. It takes the previous state value and calculates the new state value from it.

## Treat state as read-only

In React, the state is considered to be read-only, because it should not be modified directly. Instead, we should use the `set` function returned by the `useState()` to update a state.

Modifying the state variable directly can lead to unpredictable behaviour, as React may not be able to detect the change and trigger a re-render.

```javascript
function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    // 🚩 Don't modify the count directly:
    count = count + 1;
  
   // ✅ Use set function to update the count:
    setCount(count + 1);
  }
  // ..... 
}
```

### Updating objects and arrays in the state

When updating an array or an object, we need to be aware of a few important things.

**Updating objects:**

As we know that states are read-only, so we should create a new object with updated properties, and replace the state with the new object, instead of modifying the existing one.

For example, suppose the state has a position object with two properties: `x` and `y`.

```javascript
 const [position, setPosition] = useState({ x: 0, y: 0 });
```

Now if we want to update the `x` , then we need to replace the state with a new object, instead of directly updating `x`.

First, we can copy the previous object with the spread operator, and override the properties that we want to modify.

```javascript
// 🚩 Don't modify an object in state like this:
position.x = 5;

// ✅ Replace state with a new object
const newObject = {
    ... position,
    x: 5
}
setForm(newObject); // set newObject to state
```

**Updating Arrays in State**

Similar to objects, we should not modify arrays in the state directly, instead, we should create a new array with updated values and then set the state to use the new array.

```javascript
const initialMovies = [
  { id: 0, title: 'Batman', rating: 8 },
  { id: 1, title: 'Superman', rating: 7 },
  { id: 2, title: 'Ironman', rating: 8.2 },
];  
const [movies, setMovies] = useState(initialMovies);
```

Most often we need to perform the following operations on the array state: add, update or delete an item.

We can use array methods like `map` and `filter` to modify the array because they return a new array without modifying the original array.

**Adding an item to the state array:**

```javascript
addMovie(movie){
   // create a new array with new movie
  const newArray = [...movies, movie];
  setMovie(newArray); // Replace state with new array
}
```

**Removing an item from the state array:**

```javascript
deleteMovie(movieId){
  // create new array by removing movie
  const newArray = movies.filter( movie => movie.id != movieId );
  setMovie(newArray); // Replace state with new array
}
```

**Update an item in the state array:**

```javascript
updateMovie(movieId){
  const newArray = movies.map( movie => {
        if(movie.id === movieId){
            // Create a *new* object with changes
            return { ...movie, rating: 8.6 }    
        }else{
            // no changes    
            return movie;
        }
  });
  setMovie(newArray); // Replace state with new array
}
```

## Summary:

To help you remember the most important things about the `useState()`, keep these points in mind:

* It allows the functional component to manage the state.
    
* It takes an initial state value as an argument and returns an array of two items: the current state value and a function to update the state.
    
* It is important to remember that state updation is asynchronous and that multiple state updates may be batched together for performance reasons.
    
* When updating a state that depends on the previous state, we should use the updater function syntax to avoid unwanted behaviour.
    
* The state is considered to be read-only, we should not modify state variables directly.
    
* We should always use the `set` update function to update state variables.
    

---

### References

* [react.dev](https://react.dev/)
    
* [https://react.dev/reference/react/useState](https://react.dev/reference/react/useState)
