Decoding The React useState hook
Tags: react, javascript, webdev, programming
Published: 2022-06-09 23:58:51


## What is useState ?

`useState` is a React Hook that lets you add a state variable to your component.

```jsx
const [state, setState] = useState(initialState)
```

---

## Adding state to a component

Call `useState`at the top level of your component to declare one or more [state variables](https://beta.reactjs.org/learn/state-a-components-memory).

```jsx
import { useState } from 'react';

function MyComponent() {
  const [age, setAge] = useState(21);
  const [name, setName] = useState('vedanth');

// ...
```

The convention is to name state variables like `[something, setSomething]` using array destructuring.

`useState` returns an array with exactly two items:

1. The current state of this state variable, initially set to the initial state you provided.
2. The `set` function that lets you change it to any other value in response to interaction.

To update what’s on the screen, call the `set` function with some next state:

```jsx
function handleClick() {
  setName('Batman');
}
```

React will store the next state, render your component again with the new values, and update the UI.

---

### What are state variables ?

Components often need to change what’s on the screen as a result of an interaction. Like typing into the form should update the input field, clicking “next” on an image carousel should change which image is displayed, clicking “buy” should put a product in the shopping cart and so on. 

Components need to “remember” things: the current input value, the current image, the shopping cart and so on. In React, this kind of component-specific memory is called *state.*

So what is the difference between a regular variable and a state variable ?

In React 

1. **Local variables don’t persist between renders.** When React renders this component a second time, it renders it from scratch—it doesn’t consider any changes to the local variables.
2. **Changes to local variables won’t trigger renders.** React doesn’t realize it needs to render the component again with the new data.

So if we try to change something on the UI by changing a regular variable, react will not trigger a render and so nothing will change on the screen.

To update a component with new data, two things need to happen:

1. **Retain** the data between renders.
2. **Trigger** React to render the component with new data (re-rendering).

The `[useState](https://beta.reactjs.org/apis/usestate)` Hook provides those two things:

1. A **state variable** to retain the data between renders.
2. A **state setter function** to update the variable and trigger React to render the component again.

Lets try to understand this with an example to understand better.

This is counter and we are trying to update the count with a regular value

```jsx
import React from "react"

export default function App() {
  let count = 0;

  function handleClick() { 
    count = count + 1;
  }

  return (
    <>
      <h1> {count} <h1>
      <button onClick={handleClick}>
        increase count
      </button>
    </>
  );
}
```

In the example above, React will not trigger a re-render an so nothing will change on the UI.

To solve this we need to use a state variable, 

```jsx
import React, { useState }  from "react"

export default function App() {
  const [count, setCount] = useState(0);

  function handleClick() { 
    setCount(count + 1);
  }

  return (
    <>
      <h1> {count} <h1>
      <button onClick={handleClick}>
        increase count
      </button>
    </>
  );
}
```

React will store the next state, render your component again with the new values, and update the UI.

---

<aside>
💡 Calling the `set`function **does not** change the current state in the already executing code:

</aside>

```jsx
 function handleClick() { 
    setCount(count + 1);
    console.log(count) // still 0
  }
```

It only affects what `useState` will return starting from the *next* render.

---

A few examples using `useState`

1. Counter

In this example, the `count` state variable holds a number. Clicking the button increments it.

[https://stackblitz.com/edit/react-ts-fxpjaa?embed=1&file=App.tsx](https://stackblitz.com/edit/react-ts-fxpjaa?embed=1&file=App.tsx)

1. Text field

 In this example, the `text`state variable holds a string. When you type, `handleChange`
 reads the latest input value from the browser input DOM element, and calls `setText`
 to update the state.

[https://stackblitz.com/edit/react-ts-tpwd62?embed=1&file=App.tsx](https://stackblitz.com/edit/react-ts-tpwd62?embed=1&file=App.tsx)

1. Checkbox

In this example, the `liked` state variable holds a boolean. When you click the input, `setLiked`
updates the `liked` state variable with whether the browser checkbox input is checked. The `liked` variable is used to render the text below the checkbox.

[https://stackblitz.com/edit/react-ts-7fw6wv?embed=1&file=App.tsx](https://stackblitz.com/edit/react-ts-7fw6wv?embed=1&file=App.tsx)

---

### How to u**pdate state based on the previous state**

Suppose the count is `10`. This handler calls `setCount(count + 1)` three times:

```jsx
function handleClick() {
  setCount(count + 1); // setCount(10 + 1)
  setCount(count + 1); // setCount(10 + 1)
  setCount(count + 1); // setCount(10 + 1)
}
```

However, after one click, `count` will only be `11` rather than `13`! This is because calling the `set` function does not update the `count` state variable in the already running code. So each `setCount(count + 1)` call becomes `setCount(11)`.

To solve this problem, **you may pass an *updater function*** to `setCount` instead of the next state:

```jsx
function handleClick() {
  setCount(c => c + 1); // setCount(10 => 11)
  setCount(c => c + 1); // setCount(11 => 12)
  setCount(c => c + 1); // setCount(12 => 13)
}
```

Here, `c => c + 1` is your updater function. A *function* that calculates the next state based on the previous one in the queue.

It is a way to tell React to “do something with the state value” instead of just replacing it.

React puts your updater functions in a [queue](https://beta.reactjs.org/learn/queueing-a-series-of-state-updates). Then, during the next render, it will call them in the same order:

1. `c => c + 1` will receive `10` as the pending state and return `11` as the next state.
2. `c => c + 1` will receive `11` as the pending state and return `12` as the next state.
3. `c => c + 1` will receive `12` as the pending state and return `13` as the next state.

There are no other queued updates, so React will store `13` as the current state in the end.

By convention, it’s common to name the pending state argument for the first letter of the state variable name, like `c` for `count`. However, you may also call it like `prevCount` or something else that you find clearer.

What about this event handler? What do you think `number` will be in the next render?

```jsx
const [number, setNumber] = useState(0);

<button onClick={() => {
  setNumber(number + 5);
  setNumber(n => n + 1);
}}>

// Yes you're right , number will be 6
```

<aside>
💡 React may call your updaters twice in development to verify that they are [pure](https://beta.reactjs.org/learn/keeping-components-pure).

</aside>

---

### **How to update objects and arrays in state**

You can put objects and arrays into state. In React, state is considered read-only, so **you should *replace* it rather than *mutate* your existing objects**. For example, if you have a `form` object in state, don’t update it like this:

```jsx
// 🚩 Don't mutate an object in state like this:
form.firstName = 'Vedanth';
```

Instead, replace the whole object by creating a new one:

```jsx
// ✅ Replace state with a new object
setForm({
  ...form,
  firstName: 'Vedanth'
});
```

---

## What’s a mutation?

You can store any kind of JavaScript value in state.

```jsx
const [x, setX] = useState(0);
```

If you’ve  working with numbers, strings, and booleans. These kinds of JavaScript values are “immutable,” meaning unchangeable or “read-only.” You can trigger a re-render to *replace* a value:

```jsx
setX(5);
```

The `x` state changed from `0` to `5`, but the *number `0` itself* did not change. It’s not possible to make any changes to the built-in primitive values like numbers, strings, and booleans in JavaScript.

Now consider an object in state:

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

Technically, it is possible to change the contents of *the object itself*. **This is called a mutation:**

```jsx
position.x = 5;
```

However, although objects in React state are technically mutable, you should treat them **as if** they were immutable—like numbers, booleans, and strings. Instead of mutating them, you should always replace them.

In other words, you should **treat any JavaScript object that you put into state as read-only.**

Lets try to understand this with some examples 

This example holds an object in state to represent the current pointer position. The red dot is supposed to move when you touch or move the cursor over the preview area.

[https://stackblitz.com/edit/react-ts-tmrc2q?embed=1&file=App.tsx](https://stackblitz.com/edit/react-ts-tmrc2q?embed=1&file=App.tsx)

**Using a single event handler for multiple fields**

[https://stackblitz.com/edit/react-ts-crzvrd?embed=1&file=App.tsx](https://stackblitz.com/edit/react-ts-crzvrd?embed=1&file=App.tsx)

Consider a nested object structure like this:

```jsx
const [person, setPerson] = useState({
  name: 'Niki de Saint Phalle',
  artwork: {
    title: 'Blue Nana',
    city: 'Hamburg',
    image: 'https://i.imgur.com/Sd1AgUOm.jpg',
  }
});
```

If you wanted to update `person.artwork.city`, it’s clear how to do it with mutation:

```jsx
person.artwork.city = 'New Delhi';
```

But in React, you treat state as immutable! In order to change `city`, 

```jsx
setPerson({
  ...person, // Copy other fields
  artwork: { // but replace the artwork
    ...person.artwork, // with the same one
    city: 'New Delhi' // but in New Delhi!
  }
});
```

---

### How to u**pdate arrays without mutation**

In JavaScript, arrays are just another kind of object. Like with objects, **you should treat arrays in React state as read-only**. This means that you shouldn’t reassign items inside an array like `arr[0] = 'bird'`, and you also shouldn’t use methods that mutate the array, such as `push()`
and `pop()`.

Instead, every time you want to update an array, you’ll want to pass a *new* array to your state setting function. To do that, you can create a new array from the original array in your state by calling its non-mutating methods like `filter()`and `map()`. Then you can set your state to the resulting new array.

Lets understand with a few examples.

1. **Adding to an array**

`push()` will mutate an array, which you don’t want:

```jsx
setArtists( // Replace the state
  [ // with a new array
    ...artists, // that contains all the old items
    { id: nextId++, name: name } // and one new item at the end
  ]
);
```

```jsx
setArtists([
  { id: nextId++, name: name },
  ...artists // Put old items at the end
]);
```

1. **Removing from an array**

The easiest way to remove an item from an array is to *filter it out*. In other words, you will produce a new array that will not contain that item. To do this, use the `filter` method, for example:

```jsx
setArtists(
  artists.filter(a => a.id !== artist.id)
);
```

I hope this blog helped you understand useState hook better.