In this article, we will learn about the useState hook in React, why it is used, and learn its implementation with the help of examples.
What is useState hook in React?
useState() hook allows one to declare a state variable inside a function. It should be noted that one use of useState() can only be used to declare one state variable. It was introduced in version 16.8.
Reason to choose useState hook
Functional components are some of the more commonly used components in ReactJS. Most developers prefer using functional components over class-based components for the simple reason that functional components require less coding (on the developer’s part). However, two main features for the class are lost when one goes with a functional component – a dedicated state that persists through render calls as well as the use of lifecycle functions to control how the component looks and behaves at separate stages of its lifecycle.
Importing useState hook:
To import the useState hook, write the following code at the top level of your component
import { useState } from "react";
Structure of useState hook
This hooks takes some initial state and returns two value. First value contains the state and the second value is a function which updates the state. The value passed in useState will be treated as the default value
Syntax:
const [var, setVar] = useState(0);
Internal working of useState hook
The working of useState() might seem weird at first. After all, with every render, the function being rendered is a new one – how does the ‘state’ persist then? Behind the scenes, there’s an object representing the functional component in the memory, which has a stack of its own. Whenever the useState() hook is used, the value of the state variable is changed and the new variable is stored in a new cell in the stack. The stack pointer is incremented simultaneously to point toward the last cell. The value pointed to by this stack pointer is used after every render. On a deliberate refresh from the user, the stack is dumped, and a fresh allocation in the memory is done when the component is rendered.
Example: Program to demonstrate the basic use of useState() hook.
Filename- App.js: Create a React app and edit the App.js file in src folder as:
javascript
import React, { useState } from 'react' ; function App() { const click = useState( 'GeeksForGeeks' ); return ( <h1>Welcome to {click}</h1> ); } export default App; |
Output:
The value returned by useState() consists of an array with two values. The first value is the initial (or starting) value of the state variable, while the second value is a reference to the function that can be used to update the variable. One can always use array destructuring to assign both values at once so that they can be used in the component. Of course, they can also be assigned separately by assigning a variable with useState() and assigning its first index to one variable and its second index to another (destructuring just makes this easier).
Updating state using useState hook
To update states using useState we will use the second value passed in useState hook which updates the first value
Example: Program to demonstrate the use of a state variable in a functional component and how to update it accordingly.
Filename- App.js
javascript
import React, { useState } from 'react' ; function App() { const [click, setClick] = useState(0); // using array destructuring here // to assign initial value 0 // to click and a reference to the function // that updates click to setClick return ( <div> <p>You clicked {click} times</p> <button onClick={() => setClick(click + 1)}> Click me </button> </div> ); } export default App; |
Output:
Example: Program to demonstrate the use of the last value while updating the value of the ‘state’ variable.
Filename- App.js
javascript
import React, { useState } from 'react' ; function App() { const [click, setClick] = useState(0); return ( <div> <p>You 've clicked {click} times!</p> <p>The number of times you have clicked is {click % 2 == 0 ? ' even! ' : ' odd!'}</p> <button onClick={() => setClick(click => click + 1)}> Click me </button> </div> ); } export default App; |
Output:
Note that in the above example, we are using an arrow function inside setClick() that fetches the previous value of click and uses it to update it with the new value. This form is useful in cases where it is necessary to perform data manipulations based on the value of the state variable.
Updating arrays and object using useState hook
Sometimes we only want part of a state object to be updated instead of the whole state to do that we use the spread operator to fetch previous values and then add the new value
Example: Program to demonstrate the use of arrays as a state variable (using useState()).
Filename- App.js
javascript
import React, { useState } from 'react' ; function App() { const [click, setClick] = useState([]); const addNumber = () => { setClick([ ...click, { id: click.length, value: Math.random() * 10 } ]); }; return ( <div> <ul> {click.map(item => ( <li key={item.id}>{item.value}</li> ))} </ul> <button onClick={addNumber}> Click me </button> </div> ); } export default App; |
Output:
useState() works differently from the setState() function (which is used to change the value of state variables in class-based components) when it comes to using arrays. setClick() does not merge new values with the existing ones on being called, it simply overwrites them with the new value. Hence, it is necessary to find a workaround for appending the existing values, which is done inside the addNumber() internal function with the help of the spread operator. The function creates a new variable with a certain id and value and adds it to the existing array (whose values are copied into the function using the spread operator).
If one needs to deal with multiple types of data at once, the best way to go for is with an object. While the same work can be done with separate state variables, objects make work much more efficient in the long run (also one can make do with fewer useState() declarations).
Example: Program to demonstrate the use of objects as a state variable (using useState()).
Filename- App.js
javascript
import React, { useState } from 'react' ; function App() { const [data, setData] = useState({ username: '' , password: '' }); const [form, setForm] = useState({ username: '' , password: '' }); const [submit, submitted] = useState( false ); const printValues = e => { e.preventDefault(); setForm({ username: data.username, password: data.password }); submitted( true ); }; const updateField = e => { setData({ ...data, [e.target.name]: e.target.value }); }; return ( <div> <form onSubmit={printValues}> <label> Username: <input value={data.username} name= "username" onChange={updateField} /> </label> <br /> <label> Password: <input value={data.password} name= "password" type= "password" onChange={updateField} /> </label> <br /> <button>Submit</button> </form> <p>{submit ? form.username : null }</p> <p>{submit ? form.password : null }</p> </div> ); } export default App; |
Output:
In the above example, the ‘data’ variable is used to temporarily store the entered values for the username and password fields. The spread operator is used again, to copy the existing value of the fields and update it accordingly. The ‘form’ variable is used to store the value of the values submitted through the form used in the component – which is then displayed below the form. Note that the spread operator isn’t used with setForm() while updating the ‘form’ state variable for the simple reason that one does not need to be bothered about the previously submitted values of the username and password fields.