React useState Hook

React useState Hook

The useState Hook is the most commonly used Hook in React. It allows you to add state variables to functional components. State is simply data that changes over time, and when state changes, React automatically re-renders the component to reflect the new data on the screen.


Importing useState

To use useState, you must first import it from the react library at the top of your component file:

import React, { useState } from 'react';

Basic Syntax and Usage

The useState Hook is a function that takes one argument: the initial state. It returns an array containing two items:

  1. The current state value.
  2. A function that lets you update the state.

We use JavaScript array destructuring to assign names to these two items.

import React, { useState } from 'react';

function FavoriteColor() { // Declare a state variable named "color" with an initial value of "red" const [color, setColor] = useState("red");

return ( <div> <h1>My favorite color is {color}!</h1> <button onClick={() => setColor("blue")}>Blue</button> <button onClick={() => setColor("green")}>Green</button> </div> ); }

In the example above, color is our state variable. When the user clicks the "Blue" button, the setColor function is called with the value "blue". React then updates the state and re-renders the component.


Updating State Based on Previous State

When you need to update a state variable based on its current value (like incrementing a counter), you should pass an updater function to your state updater rather than just passing the new value directly.

This is crucial because state updates can be asynchronous. If multiple updates happen rapidly, relying on the state variable directly might lead to incorrect calculations.

Less Reliable Example:

<button onClick={() => setCount(count + 1)}>Increment</button>

Highly Reliable Example (Using Updater Function):

<button onClick={() => setCount(prevCount => prevCount + 1)}>Increment</button>

The prevCount parameter is guaranteed by React to hold the most up-to-date state value.


State Can Hold Any Data Type

The useState Hook isn't limited to strings or numbers. You can store booleans, arrays, objects, and even functions in state.

function UserInfo() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [hobbies, setHobbies] = useState(["Reading", "Coding"]);
  

// Using an Object in state const [user, setUser] = useState({ name: "John Doe", age: 28, email: "john@example.com" });

// ... }


Updating Objects and Arrays in State

When you use useState with objects or arrays, it is extremely important to remember that you must never mutate the existing state directly. Instead, you must create a new copy of the object or array, modify the copy, and pass the copy to the updater function.

The spread operator (...) is very helpful for this.

Updating an Object

function UserProfile() {
  const [user, setUser] = useState({
    firstName: "Jane",
    lastName: "Smith",
    role: "Admin"
  });

const updateRole = () => { // DO NOT DO THIS: user.role = "Super Admin"; // DO THIS: Spread the existing object, then overwrite the specific property setUser(prevUser => { return { ...prevUser, role: "Super Admin" }; }); };

return ( <div> <p>Name: {user.firstName} {user.lastName}</p> <p>Role: {user.role}</p> <button onClick={updateRole}>Upgrade Role</button> </div> ); }

By spreading ...prevUser, we ensure that firstName and lastName remain unchanged while only updating role.


Exercise

?

What is the most reliable way to increment a state counter named count by 1?