React Hooks: useState
A deep dive into writing functional React code that keeps track of data.
Prerequisite
JSX, JavaScript, JavaScript ES6
Introduction
What was your first thought when you heard about React Hooks? Have you ever wondered whether a real hook and react hooks are related? If we know anything, it's that most programming naming conventions tend to be descriptive of the capability of what they name.
React hooks, therefore, offer a means to latch onto, or if you prefer, hook into React's built-in functionalities. React hook usage has several guidelines, the most important of which is: Hooks should only be used inside React Components. Only React components may utilize hooks; they are not permitted in conditional statements, loops, JavaScript functions, or classes.
The useState hook, one of roughly 15 predefined hooks in React, will be the subject of this tutorial.
What is useState?
React's useState hook lets us monitor a component's state or value. When specific properties are modified, the initial state of that property is updated and the new value is preserved.
Strings, numbers, booleans, arrays, objects, and functions can all be stored in useState
. useState
allows the use of any data that may be kept in a variable.
To use useState in your React project, you have to import it from react
with this syntax:
import { useState } from 'react';
This tells us something about the useState hook: It is a named export from react
.
useState
hook returns an array that contains two elements, the current value of a property and a function that can be used to update that property.
Consider what I get on the console when I log the useState
hook.
import React, { useState } from "react";
const App = ()=> {
const val = useState();
console.log(val)
}
The result on the console looks like this:
The return value is an array that contains an undefined variable and function.
If I were to pass in a string to useState
, its return value would be different.
const App = ()=> {
const val = useState("Hello World");
console.log(val)
}
Now the results are different. We have the first element in the array set to the "Hello World" string passed into useState
.
That was an interesting dive into the return values of useState in two different conditions. Let’s now look at the syntax for writing useState
.
Syntax
We now know that useState
returns an array of two elements. So what is the best way to access these elements? We might consider using array indexing to retrieve the contents of the array but that is not the conventional way. The convention is to use an array destructuring assignment to access useState
return values.
import React, { useState } from "react";
const App = ()=> {
const [ val, setVal ] = useState("Hello World");
console.log(val, setVal)
}
Now, it is clear how these two values are stored, soon we will see how they can be used.
It is important to note that although I stored these values in variables named val
and setVal
, these are not default variable names. You may decide to name yours milk
and chocolate
or yin
and yang
, and everything would work just fine. But it is worth mentioning that by convention, the function name must be prefixed with “set” accompanied by the name of the variable. So if you choose a variable named value
then your function would, by convention, be named setValue
.
How to use useState Hook: With a variable
What is a basic programming tutorial without a “Hello World” example? This example will show how useState can be used to change some text from a random name to “Hello World”.
import React, { useState } from "react";
// App component
const App = ()=> {
// Destructuring useState
const [name, setName] = useState("Joseph Afolabi");
// Function that handles the click event
const clicked = ()=>{
setName("Hello World")
}
return (
<>
<h1>{name}</h1>
<button onClick={()=> clicked()}>Change Name</button>
</>
);
}
Explanation:
The code above defines an App
component and therein, it sets the values for useState
to name
and setName
.
The default value for the name variable is “Joseph Afolabi”. This is rendered to the DOM.
Also, a click event handler function has been defined as clicked
and it uses the setName
function to update the string stored in the name variable from what it was to "Hello World".
You might have noticed that I called the clicked
function within arrow functions. Why?
The simple explanation is, if it wasn’t done that way, the event listener fires once the page loads. To dive deeper, read here.
Another thing worth noting is how useState
was used only within the React component.
Output:
Before the button is clicked, our application looks like this:
Once the button is clicked, the value of the name variable is updated to “Hello World” and simultaneously re-rendered to the DOM.
You might have noticed that I called our clicked function within arrow functions. Why?
The simple explanation is, if it wasn’t done that way, the event listener fires once the page loads. To dive deeper, read here.
Another thing worth noting is how useState was used only within the React component.
How to use useState Hook: With an array
In this example, we will work with an array that contains random numbers. Our goal is to create a number card for each number. We will include a button on each number card that multiplies the number by 2.
First, we write the array that stores the numbers:
const numbersArray = [
{
id: 0,
number: 12,
},
{
id: 1,
number: 51,
},
{
id: 2,
number: 47,
},
{
id: 3,
number: 11,
}
]
It is important that we include a unique id for each number because in react, every child of an iterable that will be rendered to the DOM must possess a unique key attribute.
Next, we write the App component:
const App = ()=> {
const [numbers, setNumbers] = useState(numbersArray);
return (
<React.Fragment>
{
numbers.map((num) => {
const {id, number} = num;
return(
<div key={id}>
<h3>{number}</h3>
<button onClick={ () => {multiply(id)} }>Multiply</button>
</div>
)
})
}
</React.Fragment>
);
}
Explanation:
Within the App
component, we set the default value of useState
to the numbersArray
declared earlier.
The array elements are iterated over, data is extracted and rendered to the DOM.
When the button is clicked, we expect a function to carry out the click event and implement the functionality. This function has been called in the button as multiply
.
Now, let's define the multiply
function
const multiply = (id) => {
setNumbers(numbers.map((num) => {
if (num.id == id){
num.number = num.number * 2;
}
return (num)
}))
Explanation:
This function takes the id of each array element as parameter. We will see why in a moment.
Next, it retrieves it array stored in numbers
array in its present state. It iterates over each of the element, checking for the element whose id property matches the id passed to it.
When it finds a match, it multiplies the number by 2, otherwise it return the original value.
Finally, it returns a new array.
Output:
With a little bit of styling, out result looks like this:
If I click the button beside 12 and the button beside 47, the result is shown below:
Both numbers have been doubled.
How to use useState Hook: With an object
Updating the state of the properties in an object is quite easy. Technically, we have used an object in our previous example.
However, consider an example of an object that holds information about an employee. In this object, we would define the name, gender, and image of the employee.
const employee = {
name: "Udoh Biliki",
img: "https://res.cloudinary.com/diqqf3eq2/image/upload/v1595959131/person-2_ipcjws.jpg",
gender: "Male"
}
Next, we would define the Employee
component and therein initialize useState
with the employee
object.
const Employee = () => {
const [person, setPerson] = useState(employee);
return (
<>
<img src={person.img}></img>
<div>
<h3>{person.name}</h3>
<p>{person.gender}</p>
</div>
<button onClick={changeGender}>
change Message
</button>
</>
)
};
Explanation:
The employee
object was set as the default value of useState
. Although the object could be defined directly in useState
, I think it's better to set it into a variable as we have done.
Next, the object is destructured and its properties are passed into JSX tags to be rendered into the DOM.
Pretty simple, isn't it?
But what happens when you would like to update one of the properties in the object?
For instance, I have set the gender to male but the Image shows that this employee is female. A function has been called to handle that event. It is defined below:
const changeMessage = ()=> {
setPerson({...person, gender: "Female"})
if (person.gender === "Female")
setPerson({...person, gender: "Male"})
}
Explanation:
This function updates the state of the object, here represented as person.
The change is done on line 2. setPerson
updates the object by making a shallow copy of all properties of the person object except the message property that it needs to update.
The …person
expression makes a shallow copy of the object using an ES6 syntax called spread operator.
This functionality was implemented with just one line of code. The if statement is just a little bit of extra functionality that lets the button toggle gender
to either male or female.
Now you can guess what the result would be when the button is clicked:
You guessed right!
Practice example: Build a class list of students
This article wouldn't be complete without a little task to cement all that has been learned. So here is a simple task to practice with.
Given an array of objects containing basic information about students, build a student list that displays each student’s image, name, and class.
You can choose whatever design you would like to use.
Functionality:
You should be able to remove each student from the list
You should be able to increment and decrement the class
You should be able to remove all students
Hence, you should have a total of three buttons on each student card and one button that clears all students.
This is a fun way to learn to use useState, you will learn a lot on the journey.
Conclusion
This article has provided a mid-level view of useState, yet these are not the most complex use cases. Try your hands on more complex examples and build as many real-life projects as you can.
Happy hacking!