useState Hook In React
Tags: react, javascript, beginners, webdev
Published: 2022-09-18 18:29:50

## 🎯 What are Hooks?

- Hooks are a new feature addition in React version 16.8 which allows you to use React features without having to write a class.
- Previously you could use state only within class components but with hooks now it is possible to use state without writing a class. 
- Hooks don't work inside classes.

## 🎯 Why Hooks?

- To work with classes you have to understand how **this** keyword works in javascript. You also need to remember to bind event handlers in class components.
- Classes don't minify very well and make hot reloading very unreliable.
- Hooks help to reuse stateful component logic without changing the component hierarchy.
- Rather than forcing a split based on the lifecycle methods, hooks let you split one component into smaller functions based on what pieces are related.

## 🎯 Rules of Hooks
- Only call hooks at the "Top Level" of your react functions
- Don't call hooks inside loops, conditions, or nested functions.
- Only call hooks from React functions. Call them from within React functional components and not just any regular javascript function.

Now let's learn about the very first hook- **useState** hook.
 
We will try to understand this using a simple example.

In our example, we'll create a simple button that will increment the value of the counter on the `onClick` event.

![useState-class-component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v3b0rorrwn2k41m2ja6u.gif)

## 🎯 Manage State using Class Component

First, we'll look at how to implement the same using the **class component**.

- Create a class component
- Create a `state` variable and initialized it to 0.
- Create a method that is capable of setting this state value.


```javascript
import React, { Component } from 'react';

class ClassCounter extends Component {

  constructor(props){
    super(props);

    this.state = {
      count: 0
    }
  }

  handleIncrement = () => {
    this.setState({
      count: this.state.count + 1
    })
  }

  render() {
    return (
      <div>
        <button onClick={this.handleIncrement}>
           Increment Value
        </button>
        <p>{this.state.count}</p>
      </div>
    )
  }
}

export default ClassCounter;

```

## 🎯 useState Hook

- `useState` is a hook that lets you maintain react state to functional components.
- Hooks are just functions so we simply call them. 
- This hook accepts an argument defining the initial value of the state property. 
- It returns the pair of values. `current value` of the state property and a `method` that is capable of updating that state property.

### 📌 Manage State using Functional Component

Now let's take a look at how to implement the above example using a **functional component**. 

- Create a functional component
- We need a `state` property initialized to 0.
- We need a method capable of setting that state property value.
- Syntax which we have used below in `const [counter, setCounter] = useState(0);` is called **Array Destructuring**
- The variable `counter` will always contain the current state value and `setCounter` will accept an argument and set a counter value to that argument. 

```javascript
import React, { useState } from 'react';

export const FunctionalCounter = () => {
  const [counter, setCounter] = useState(0);

  const handleIncrement = () => {
    setCounter(counter + 1);
  }
  
  return (
    <div>
      <button onClick={handleIncrement}>
         Increment Value
      </button>
      <p>{counter}</p>
    </div>
  )
}

```

Notice the usage of `useState` hook in the above code snippet. 

- A very first time the component renders a state variable is created and initialized with the default value of 0. The default value is never used on re-renders. 
- When you click on the button the `setCounter` method is called which will add 1 to the current counter value.
- `setCounter` method will cost the component to re-render. 
- After the re-render counter will contain the updated value. 

### 📌 useState with previous state

Now let's take a look at an example where we'll see how to update the state based on the previous state.

Let's say, we want to implement the count value by 5 each time user clicks on the button.

Let's write a code for the same.

```javascript
import React, { useState } from 'react';

export const FunctionalCounterWithPreviousState = () => {
  const [counter, setCounter] = useState(0);

  const handleIncrement = () => {
    for(let i = 0; i < 5; i++){
      setCounter(counter + 1);
    }
  }

  return (
    <div>
      <button onClick={handleIncrement}>
          Increment Value
      </button>
      <p>{counter}</p>
    </div>
  )
}

```

![useState-class-component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v3b0rorrwn2k41m2ja6u.gif)

When we'll run the above code snippet you will notice that it will not work as expected. But Why?? 

Here comes the concept of **Batch Rendering.**

#### ✏️ Batch Rendering

React may batch multiple `setState()` calls into a single update for performance.

The main idea is that no matter how many setState calls you make inside a React event handler or synchronous lifecycle method, it will be batched into a single update. That is only one single re-render will eventually happen.

This functionality is relevant for both hooks and regular class components, and its purpose is to prevent unnecessary rendering.

As React updates the state **Asynchronously**, you should not rely on their values for calculating the next state.

_________________________________________________________________

So what other way we can use to achieve our target? Now we'll use the second form of the `setCounter` function.

Basically, instead of passing in a value of the new state variable, we pass in the function that has access to the old state value.

So now we'll update our code as follows:

```javascript
import React, { useState } from 'react';

export const FunctionalCounterWithPreviousState = () => {
  const [counter, setCounter] = useState(0);

  const handleIncrement = () => {
    for(let i = 0; i < 5; i++){

       // Update the value based on the previous value
      setCounter(prevCounter => prevCounter + 1);
    }
  }

  return (
    <div>
      <button onClick={handleIncrement}>Increment Value</button>
      <p>{counter}</p>
    </div>
  )
}

```

![useState-batch-rendering.gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rzs072l4ip1f6ekyryl6.gif)

Now it will work as expected.

### 📌 useState with Objects

Now we will use an object as a state variable with the useState hook. 
So instead of storing a variable, we will work with objects this time.

In the below example, we will initialize the state variable with an object with **firstName** & **lastName** as a key. 

Let's take a look at the code first.

```javascript
import React, { useState } from 'react';

const HooksWithObject = () => {
  const [name, setName] = useState({firstName: '', lastName: ''});

  return(
    <div>
      <div>
        <label>Enter FirstName: </label>
        <input 
          type='text' 
          value={name.firstName} 
          onChange={e => setName({firstName: e.target.value})} 
        />
      </div>
      <div>
      <label>Enter LastName: </label>
        <input 
          type='text' 
          value={name.lastName} 
          onChange={e => setName({lastName: e.target.value})} 
        />
      </div>
      <p>firstName: {name.firstName}</p>
      <p>lastName: {name.lastName}</p>
    </div>

  )
}

export default HooksWithObject;

```

In the above code snippet, there are input fields that will update the values of **firstName** & **lastName** as a user types in the input fields.

![useState-with-object.gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d6swmhunnxkmhnog7ob4.gif)

As you notice above, whenever a user updates the **lastName** input field, the **firstName** input field gets reset to an empty string and removed from the state variable

- This is happening because **`useState` does not automatically merge and update the object.**

- This is the key difference between the **setState** in Class Component and **useState** in the functional Component. `setState` will merge the state whereas `useState` hook setter function will not merge the state. You can use **spread operator** to handle this situation.

So now update our code accordingly.

```javascript
import React, { useState } from 'react';

const HooksWithObject = () => {
  const [name, setName] = useState({firstName: '', lastName: ''});

  return(
    <div>
      <div>
        <label>Enter FirstName: </label>
        <input 
          type='text' 
          value={name.firstName} 
          onChange={e => setName({...name, firstName: e.target.value})} 
        />
      </div>
      <div>
      <label>Enter LastName: </label>
        <input 
          type='text' 
          value={name.lastName} 
          onChange={e => setName({...name, lastName: e.target.value})} 
        />
      </div>
      <p>firstName: {name.firstName}</p>
      <p>lastName: {name.lastName}</p>
    </div>

  )
}

export default HooksWithObject;

```

In the above code snippet, while setting the name variable on `onChange` event, we'll first copy every property in the name object and then just overwrite the **firstName** field with a different value.

Now when we'll check our result. It will work as expected.

![useState-with-spread-object.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1663516780931/eul00Sz44.gif align="left")



## 🎯 Summary

- The useState hook allows you to maintain a state inside functional components.
- In classes, the state is always an object. With the useState hook, the state doesn't have to be an object. It can be an array, number, boolean or string, etc.
- The useState hook returns an array with 2 elements. The first element is the current value of the state and the second element is a state setter function.
- State setter function will cause the component to re-render.
- In case your new state value depends on the previous state value you can pass a function to the setter function. The setter function will receive the previous state as its argument.
- When dealing with objects or arrays, always make sure to spread your state variable and then call the setter function.  

## 🎯 Wrap Up!!

That's all for this article. Thank you for your time!! Let's connect to learn and grow together.

[LinkedIn](https://www.linkedin.com/in/anuradha-aggarwal-4a2751107/) [Twitter](https://twitter.com/Anuradh06359394) [Instagram](https://www.instagram.com/blogcode404/)

[![Buy-me-a-coffee](https://cdn.buymeacoffee.com/buttons/v2/default-blue.png)](https://www.buymeacoffee.com/anuradha2612)