ReactJS useState Hook

The useState Hook is the foundation of state management in modern React. It allows functional components to store and update data that changes over time, enabling interactive and dynamic user interfaces.

Any data that can change over time—such as user input, counters, toggles, or fetched values—is handled using state. In modern React, the useState Hook is the primary way to manage state inside functional components.

What Is State in React?

State is data that belongs to a component and can change over time. Examples of state:

  • Counter value
  • Input text
  • Toggle (true / false)
  • Selected item

When state gets updated(changes), React automatically re-renders the component to reflect the new data.

State is:
  • Local to the component
  • Managed by React
  • Used to control UI behavior

Why do we need useState?

In functional components, plain variables do not persist between renders.


let count = 0;

This value resets every time the component re-renders.

useState is required because:
  • It stores data across renders
  • React tracks the value internally
  • UI updates when the value changes

Without useState, functional components cannot remember data.


Importing useState (Mandatory)

To use useState, it must be imported from React.


import { useState } from "react";

If you do not import it, React will not recognize the Hook.

Basic Syntax of useState

Hooks can only be called at the Top Level of a Component


const [stateValue, setStateValue] = useState(initialValue);

Explanation:
  • stateValue → current state
  • setStateValue → function to update state
  • initialValue → value used during first render only

useState Examples – Core Patterns You Must Know

1. Initialize, Read and Display the state

First you initialize and store data in state like - useState(10), here 10 is the initial value, and then display it in JSX. This is the most basic use of useState.

Example: Displaying a number

import { useState } from "react";

function DisplayState() {
  const [count, setCount] = useState(10);

  return (
    <h2>Count value: {count}</h2>
  );
}

export default DisplayState;

Explanation:
  • count holds the state value
  • JSX reads count
  • Whenever count changes, UI updates automatically

2. Updating State

State should be updated only using the setter function.

Example: Change Color on Button Click

import { useState } from "react";

function ColorChanger() {
  const [color, setColor] = useState("Red");

  function changeColor() {
    setColor("Blue");
  }

  return (
    <div>
      <h2>Selected Color: {color}</h2>
      <button onClick={changeColor}>Change Color</button>
    </div>
  );
}

export default ColorChanger;

What’s happening here (Flow)

1. useState("Red")
  • color → current state value
  • setColor → function to update state
2. Button Click
  • changeColor() is called
3. setColor("Blue")
  • React updates the state internally
  • Component re-renders
  • New value (Blue) appears on UI

3. Reading and Updating State (Number, String, Boolean)

a) Integer State (Counter)


import { useState } from "react";

function NumberState() {
  const [age, setAge] = useState(25);

  return (
    <>
      <p>Age: {age}</p>
      <button onClick={() => setAge(age + 1)}>
        Increase Age
      </button>
    </>
  );
}

export default NumberState;


b) String State (Input)


import { useState } from "react";

function StringState() {
  const [name, setName] = useState("");

  return (
    <>
      <input
        type="text"
        onChange={(e) => setName(e.target.value)}
      />
      <p>Hello {name}</p>
    </>
  );
}

export default StringState;


c) Boolean State (Toggle)


import { useState } from "react";

function BooleanState() {
  const [isVisible, setIsVisible] = useState(true);

  return (
    <>
      <button onClick={() => setIsVisible(!isVisible)}>
        Toggle
      </button>

      {isVisible && <p>This is visible</p>}
    </>
  );
}

export default BooleanState;


4. Using State with Arrays and Objects

a) Array State

Example: Adding items to a list

import { useState } from "react";

function ArrayState() {
  const [items, setItems] = useState(["React", "JavaScript"]);

  function addItem() {
    setItems([...items, "Hooks"]);
  }

  return (
    <>
      <ul>
        {items.map((item, index) => (
          <li key={index}>
            {item}
          </li>
        ))}
      </ul>

      <button onClick={addItem}>
        Add Item
      </button>
    </>
  );
}

export default ArrayState;

What Is the Flow Here?

1. items initially holds:

["React", "JavaScript"]

2. User clicks Add Item
3. addItem() runs and calls:

setItems([...items, "Hooks"]);

4. React receives a new array reference
5. React triggers a re-render
6. UI updates with the new list

b) Object State

Example: Updating one property

import { useState } from "react";

function ObjectState() {
  const [user, setUser] = useState({ name: "John", city: "LA" });

  function changeCity() {
    setUser({ ...user, city: "NY" });
  }

  return (
    <>
      <p>{user.name} - {user.city}</p>
      <button onClick={changeCity}>
        Change City
      </button>
    </>
  );
}

export default ObjectState;

What Is the Flow Here?

1. Initial state:

{ name: "Gaurav", city: "Delhi" }

2. User clicks Change City
3. changeCity() runs:

setUser({ ...user, city: "Mumbai" });

4. React creates a new object reference
5. React compares old vs new reference
6. Component re-renders with updated data

Summary

useState is a built-in React Hook that allows functional components to store and update state. Before Hooks, state could only be used inside class components. With useState, functional components can now manage their own state and respond to user interactions.

By using useState, React takes responsibility for tracking state internally and re-rendering components whenever that state updates. This removes the need for manual DOM manipulation and keeps component logic predictable and easy to follow.

Whether you are working with numbers, text, booleans, arrays, or objects, useState provides a consistent and reliable way to manage component-level data. When used correctly—by avoiding direct mutations and always creating new state references—it helps build clean, bug-free, and maintainable React applications.