useState is React Hook that allows you to create, track and update a state variable in functional component. Let's learn How to initialise and update state using useState in React

useState in React

Table of Contents

What is useState in React?

useState is the ability to encapsulate local state in a functional component. It returns an array with two values: one is the current state value and another one is a function to update it. 

The Hook takes an initial state value as an argument and returns an updated state value whenever the setter function is called. Let's understand how to initialise and update state using useState hook in React

Syntax

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

const [stateVariable, setStateFunction] =
useState(initialStateValue)

Incorporate the useState Hook

To incorporate the useState Hook into our functional component, we first need to import it from React.

First we should import the useState Hook at the top of our functional component. That means we need to  destruct useState from react as it is a named export.


import { useState } from "react"


Initialise state variable using useState

Calling useState in our function component to initial state.

useState accepts an initial state value and it returns two values:

1.The current state.

2. A function that updates the state.

Below example, will show you how tot initialise state in functional component

Note: We should only Initialise state at the top of the function component.

import { useState } from "react"

function CounterComponent() {
const [count, setCount] =
useState(0)
}

Look at out example above, we are destructing the returned values from useState.

1. The first value, count, is our current state.

2. The second value, setCount, is the function that is used to update our state.

3. These names are just variables that can be named anything we would like.

4. Lastly, we set the initial state to an empty string: useState(0)

Anatomy of useState 

When you call useState, you are telling React that you want this component to remember something:

const [count, setCount] = useState(0)

In this case, you want React to remember count.

Note: The convention is to name this pair like const [something, setSomething]. You could name it anything you like, but conventions make things easier to understand across projects.

How to read State value

We can now include our state anywhere in our functional component.

Example:

Let's first use the state variable in the rendered component.


import { useState } from "react"

const CounterComponent = () => {
const [count, setCount] =
useState(0)
return (
<div>The current count
value {count}</div>
)
}
export default CounterComponent

Update State Value 

To update state value in our component, we  should use setter function of useState


import React from 'react'

const CounterComponent = () => {
const [count, setCount] =
useState(0)
return (
<React.Fragment>
<div>The current count
value {count}</div>

<button type="button" onClick={
() => setCount(count + 1)}
>InCrease</button>

<button type="button" onClick={
() => setCount(count - 1)}
>Decrease</button>
</React.Fragment>
)
}
export default CounterComponent


Updating state based on the previous state 

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


import React from 'react'

const CounterComponent = () => {
const [count, setCount] =
useState(0)

const handleClick = () => {
setCount(count + 1); // setCount(0 + 1)
setCount(count + 1); // setCount(0 + 1)
setCount(count + 1); // setCount(0 + 1)
}
return (
<React.Fragment>
<div>The current count
value {count}</div>

<button type="button" onClick={
() => handleClick}
>click</button>

</React.Fragment>
)
}
export default CounterComponent

However, after one click, count will only be 1 rather than 3. 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(3).



import React from 'react'

const CounterComponent = () => {
const [count, setCount] =
useState(0)

const handleClick = () => {
setCount((prevCount) => prevCount + 1) // setCount(0 + 1)
setCount((prevCount) => prevCount + 1) // setCount(1 + 1)
setCount((prevCount) => prevCount + 1) // setCount(2 + 1)
}
return (
<React.Fragment>
<div>The current count
value {count}</div>

<button type="button" onClick={
() => handleClick}
>click</button>

</React.Fragment>
)
}
export default CounterComponent


Here, prevCount => prevCount + 1 is your updater function. It takes the pending state and calculates the next state from it.

React puts your updater functions in a queue. Then, during the next render, it will call them in the same order:

prevCount => prevCount + 1 will receive 0 as the pending state and return 1 as the next state.

prevCount => prevCount + 1  will receive 1 as the pending state and return 2 as the next state.

prevCount => prevCount + 1 will receive 2 as the pending state and return 3 as the next state.


What Data Can State Store?

The useState Hook can be used to keep track of strings, numbers, booleans, arrays, objects, and any combination of these!

Let's see an example, to create multiple state Hooks to track individual values.

import React from 'react'

const TestComponent = () => {
const [count, setCount] =
useState(0)
const [name, setName] =
useState("Ng Educate")
const [loading, setLoading] =
useState(false)

return (
<React.Fragment>
<div>The current count
value {count}</div>

<div>The current Name
value {name}</div>

<div>The current Loading
value {loading}</div>

<button type="button"
onClick={() =>
setCount(count + 1)}
>InCrease Count</button>

<button type="button"
onClick={() =>
setName("NG-Educate")}
>Change Name</button>

<button type="button" onClick={
() => setLoading(true)}
>Change Loading</button>

</React.Fragment>

)
}

export default TestComponent


Updating Objects  data in State 

When  estate is updated, the entire state gets overwritten.

What if we only want to update the name of employee?

We can use the JavaScript spread operator to specific element in object.

import React from 'react'

const EmployeeComponent = () => {
const [employee, setEmployee] =
useState({
name: "Nagi",
id: 1234,
designation: "Developper"
})


const updateName = () => {
setCar(previousState => {
return {
...previousState,
name: "Ng-Educate"
}
});
}

return (
<React.Fragment>

<div>I am {employee.name}</div>

<div>My current designation
is {employee.designation}</div>

<label for="name"> Name: </label>
<input type="text" id="name"
name="name" value={employee.name}
onChange={updateName} />

</React.Fragment>

)
}

export default EmployeeComponent


Updating Arrays  data in State 

1. Passing the initializer function

This example passes the initializer function, so the createInitialItems function only runs during initialization. It does not run when component re-renders, such as when you type into the input.

import { useState } from 'react';

function createInitialItems() {
const initialItems = [];
for (let i = 0; i < 50; i++) {
initialItems.push({
id: i,
text: 'Item ' + (i + 1)
});
}
return initialItems;
}

export default function ItemList() {
const [Items, setItems] =
useState(createInitialItems);
const [text, setText] =
useState('');

return (
<>
<input
value={text}
onChange={e =>
setText(e.target.value)}
/>
<button onClick={() => {
setText('');
setItems([{
id: Items.length,
text: text
}, ...Items]);
}}>Add</button>
<ul>
{Items.map(item => (
<li key={item.id}>
{item.text}
</li>
))}
</ul>
</>
);
}


2. Passing the initial state directly

This example does not pass the initializer function, so the createInitialItems function runs on every render, such as when you type into the input. There is no observable difference in behavior, but this code is less efficient.

import { useState } from 'react';

function createInitialItems() {
const initialItems = [];
for (let i = 0; i < 50; i++) {
initialItems.push({
id: i,
text: 'Item ' + (i + 1)
});
}
return initialItems;
}

export default function ItemList() {
const [Items, setItems] =
useState(createInitialItems());
const [text, setText] =
useState('');

return (
<>
<input
value={text}
onChange={e =>
setText(e.target.value)}
/>
<button onClick={() => {
setText('');
setItems([{
id: Items.length,
text: text
}, ...Items]);
}}>Add</button>
<ul>
{Items.map(item => (
<li key={item.id}>
{item.text}
</li>
))}
</ul>
</>
);
}


you can refer react docs to learn more about useState in React