Popular Searches
Popular Course Categories
Popular Courses

useState Hook

useState Hook

React Hooks Fundamentals

React useState Hook – Complete Notes

The useState Hook is a built-in React Hook that allows functional components to store, manage, and update state. State represents information that can change while a user interacts with an application. When state changes, React renders the component again to display the updated information.

For example, the useState Hook can manage a counter, input fields, form data, login status, dropdown visibility, shopping cart items, and dark mode.

Course: JustAcademy React JS Training Course

Course Demo: Register for React JS Course Demo


1. What Is the useState Hook?

The useState Hook allows a React component to remember information between renders. It provides a state variable and a setter function that updates that variable.

Syntax:

import { useState } from 'react';
const [state, setState] = useState(initialValue);

Explanation:

  • useState: A built-in React Hook used to declare state.
  • state: The current value stored by React.
  • setState: The function used to request a state update.
  • initialValue: The value used to initialize the state during the component's first render.

2. Why Do We Need the useState Hook?

In a React component, changing a normal JavaScript variable does not automatically update the UI. A normal variable also does not retain its changed value across renders. The useState Hook solves these problems by allowing React to remember a value and render the component again when that value changes.

Example without useState:

function Counter() {
  let count = 0;
  function increment() {
    count = count + 1;
    console.log(count);
  }
  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={increment}>Increment</button>
    </div>
  );
}
export default Counter;

Problem: Clicking the button changes the local variable, but React does not automatically render the updated value. On a new render, the variable is initialized again.

Solution: Use useState to store the value and request a re-render when it changes.

3. How Does useState Work?

  1. React renders the component for the first time.
  2. The useState Hook initializes the state with the supplied initial value.
  3. React returns the current state value and its setter function.
  4. An event, such as a button click, calls the setter function.
  5. React schedules a state update and renders the component again when necessary.
  6. The component displays the latest state value.

Basic flow:

Component renders
       ↓
useState(initialValue)
       ↓
Current state + setter function
       ↓
User interaction
       ↓
Setter function called
       ↓
React updates state
       ↓
Component renders again
       ↓
Updated UI displayed

4. Basic Example: Counter Using useState

This example demonstrates how to increase a number when a user clicks a button.

import { useState } from 'react';
function Counter() {
  const [count, setCount] = useState(0);
  function increment() {
    setCount(count + 1);
  }
  return (
    <div>
      <h2>Counter: {count}</h2>
      <button onClick={increment}>Increment</button>
    </div>
  );
}
export default Counter;

Explanation:

  • useState(0) initializes the counter to zero.
  • count stores the current counter value.
  • setCount updates the counter.
  • setCount(count + 1) requests an update using the current count.
  • After React renders again, the updated number appears on the screen.

Expected result: Initially, the counter displays 0. After one click, it displays 1. After another click, it displays 2.

5. Updating State with the Previous Value

When the next state depends on the previous state, use the functional updater form. This is especially useful when multiple updates are queued during the same event.

Syntax:

setState(previousState => nextState);

Example:

import { useState } from 'react';
function Counter() {
  const [count, setCount] = useState(0);
  function incrementThreeTimes() {
    setCount(previousCount => previousCount + 1);
    setCount(previousCount => previousCount + 1);
    setCount(previousCount => previousCount + 1);
  }
  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={incrementThreeTimes}>Increase by 3</button>
    </div>
  );
}
export default Counter;

Explanation: Each updater receives the pending state value produced by the previous queued updater. Clicking the button increases the counter by three.

Important: When a new value is calculated from the previous state, prefer the functional updater form to avoid using an outdated value.

6. Different Types of State in React

The useState Hook can store different JavaScript data types.

Data Type Example Common Use
Number useState(0) Counter, quantity, score
String useState('') Name, search term, message
Boolean useState(false) Toggle, modal, visibility
Array useState([]) Todo list, products, tasks
Object useState({ name: '' }) Form data, user profile
Null useState(null) Initially unavailable data

7. Example: Updating a String State

A string state can store a user's name or any other text.

import { useState } from 'react';
function Greeting() {
  const [name, setName] = useState('Guest');
  return (
    <div>
      <h2>Hello, {name}!</h2>
      <button onClick={() => setName('Rahul')}>Change Name</button>
    </div>
  );
}
export default Greeting;

Explanation: The initial name is Guest. Clicking the button changes the state to Rahul, and the displayed greeting updates.

8. Example: Boolean State and Toggle

A boolean state stores either true or false. It is useful for showing or hiding content and controlling toggle features.

import { useState } from 'react';
function ToggleMessage() {
  const [isVisible, setIsVisible] = useState(false);
  return (
    <div>
      <button onClick={() => setIsVisible(previous => !previous)}>
        {isVisible ? 'Hide Message' : 'Show Message'}
      </button>
      {isVisible && <p>Welcome to React!</p>}
    </div>
  );
}
export default ToggleMessage;

Explanation: The initial state is false, so the message is hidden. Clicking the button changes the state to true and displays the message. Clicking again hides it.

9. Example: Managing Input Fields

The useState Hook is commonly used to create controlled input fields. In a controlled input, React state stores the current value of the field.

import { useState } from 'react';
function NameForm() {
  const [name, setName] = useState('');
  return (
    <div>
      <label htmlFor="username">Enter your name:</label>
      <input
        id="username"
        type="text"
        value={name}
        onChange={event => setName(event.target.value)}
        placeholder="Enter your name"
      />
      <p>Your name is: {name}</p>
    </div>
  );
}
export default NameForm;

Explanation:

  • value={name} connects the input value to React state.
  • onChange runs when the user types or changes the field.
  • event.target.value reads the current input value.
  • setName() updates the state, and React displays the latest value.

10. Example: Managing Multiple State Variables

A component can call useState multiple times to manage separate pieces of information.

import { useState } from 'react';
function UserProfile() {
  const [name, setName] = useState('Amit');
  const [age, setAge] = useState(22);
  const [isStudent, setIsStudent] = useState(true);
  return (
    <div>
      <h2>User Profile</h2>
      <p>Name: {name}</p>
      <p>Age: {age}</p>
      <p>Student: {isStudent ? 'Yes' : 'No'}</p>
      <button onClick={() => setName('Priya')}>Change Name</button>
      <button onClick={() => setAge(previous => previous + 1)}>Increase Age</button>
      <button onClick={() => setIsStudent(previous => !previous)}>Toggle Student</button>
    </div>
  );
}
export default UserProfile;

Explanation: The name, age, and student status are independent state variables. Updating one does not automatically change the other two.

11. Updating Objects in State

The useState Hook can store objects, which are useful for managing related form fields or profile information. State objects should be treated as read-only. Instead of modifying an existing object, create and set a new object.

Example:

import { useState } from 'react';
function Profile() {
  const [user, setUser] = useState({
    name: 'Amit',
    city: 'Mumbai'
  });
  function changeCity() {
    setUser(previousUser => ({
      ...previousUser,
      city: 'Pune'
    }));
  }
  return (
    <div>
      <p>Name: {user.name}</p>
      <p>City: {user.city}</p>
      <button onClick={changeCity}>Change City</button>
    </div>
  );
}
export default Profile;

Explanation:

  • user stores an object containing the name and city.
  • ...previousUser copies the existing properties.
  • city: 'Pune' replaces the city property.
  • The new object is passed to setUser().

Incorrect approach:

user.city = 'Pune';
setUser(user);

This mutates the existing object and passes the same reference back to React. React may ignore the update because the object reference has not changed.

12. Updating Arrays in State

Arrays can store lists of tasks, products, names, or messages. Create a new array when adding, removing, or changing items.

Example: Adding a task

import { useState } from 'react';
function TodoList() {
  const [tasks, setTasks] = useState([]);
  const [task, setTask] = useState('');
  function addTask() {
    const trimmedTask = task.trim();
    if (trimmedTask === '') return;
    setTasks(previousTasks => [...previousTasks, trimmedTask]);
    setTask('');
  }
  return (
    <div>
      <input
        value={task}
        onChange={event => setTask(event.target.value)}
        placeholder="Enter a task"
      />
      <button onClick={addTask}>Add Task</button>
      <ul>
        {tasks.map((item, index) => (
          <li key={`${item}-${index}`}>{item}</li>
        ))}
      </ul>
    </div>
  );
}
export default TodoList;

Explanation: The spread operator creates a new array containing the previous tasks and the new task. React then renders the updated list. In production lists where items can be reordered or deleted, use stable unique IDs as keys rather than array indexes.

13. Initial State and Lazy Initialization

The initial state is used when the component is initialized. React ignores the initial value argument on subsequent renders of the same component.

Simple initialization:

const [count, setCount] = useState(0);

For expensive initial calculations, pass an initializer function instead of calling the calculation directly on every render.

Example:

function createInitialCount() {
  return 100;
}
function Counter() {
  const [count, setCount] = useState(createInitialCount);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
export default Counter;

Important difference: useState(createInitialCount) passes the function as an initializer. useState(createInitialCount()) calls the function during rendering, even though React only uses the resulting value for initial state.

Initializer functions should be pure. In development Strict Mode, React may call an initializer more than once to help identify accidental side effects.

14. State Updates Are Not Immediately Reflected in the Current Code

Calling a setter requests a state update; it does not change the state variable in the currently executing code.

function handleClick() {
  setCount(count + 1);
  console.log(count);
}

The console statement reads the state value from the current render, not the value scheduled for the next render. To inspect the updated value, observe it in the next render or use an appropriate effect when a side effect genuinely depends on the committed state.

15. Common Mistakes When Using useState

Mistake Why It Is a Problem Correct Approach
Changing a normal variable Does not trigger a React re-render Use state for values that must update the UI
Calling a setter during every render Can cause repeated rendering or an infinite loop Update state in event handlers or appropriate logic
Mutating an object Can prevent React from detecting a changed reference Create a new object with spread syntax
Mutating an array Can lead to unexpected UI updates Create a new array using spread, map, or filter
Using stale values for repeated updates Queued updates may not build on the intended previous value Use a functional updater when appropriate
Calling useState conditionally Breaks the Rules of Hooks Call Hooks at the top level of the component
Expecting state to update synchronously The current render still uses its existing state snapshot Use the updated value in the next render
Using state for every calculated value Creates unnecessary duplicate state Calculate values from existing props or state when possible

16. Rules for Using the useState Hook

  • Import useState from React before using it.
  • Call useState only at the top level of a function component or a custom Hook.
  • Do not call useState inside loops, conditions, nested functions, or event handlers.
  • Use the setter function to update state rather than assigning a new value to the state variable.
  • Treat state objects and arrays as immutable; create replacements instead of mutating them.
  • Keep initializer and updater functions pure.
  • Use meaningful names such as count and setCount.

17. useState vs. Normal Variables

Feature Normal Variable useState
Retains its changed value across renders No, not by itself Yes
Triggers a re-render when changed No Setter requests an update
Suitable for UI state Usually not Yes
Example let count = 0; const [count, setCount] = useState(0);

18. useState vs. useReducer

Feature useState useReducer
Best suited for Simple or independent state values Complex state transitions and related updates
Update mechanism Setter function Dispatching actions to a reducer
Code complexity Usually simpler Requires a reducer and action logic
Example Toggle, counter, input field Complex form, multi-step workflow

19. Practical Project: Counter Application

Project objective: Create a counter with increment, decrement, and reset buttons using the useState Hook.

Features:

  • Display the current count.
  • Increase the count by one.
  • Decrease the count by one.
  • Reset the count to zero.

Code:

import { useState } from 'react';
function CounterApp() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <h1>Counter App</h1>
      <h2>Count: {count}</h2>
      <button onClick={() => setCount(previous => previous + 1)}>Increment</button>
      <button onClick={() => setCount(previous => previous - 1)}>Decrement</button>
      <button onClick={() => setCount(0)}>Reset</button>
    </div>
  );
}
export default CounterApp;

Learning outcome: This project teaches state initialization, setter functions, event handling, functional updates, and automatic UI updates through React rendering.

20. Practice Exercises

  1. Create a counter that increases and decreases by five.
  2. Create a button that switches between Light Mode and Dark Mode.
  3. Create a text field that displays the user's input below it.
  4. Create a form that stores a name, email, and city in an object state.
  5. Create a todo list that supports adding and removing tasks.
  6. Create a password visibility toggle using boolean state.
  7. Create a shopping cart counter that updates the number of items.
  8. Create a component that changes a displayed message when a button is clicked.

21. Interview Questions and Answers

Q1. What is the useState Hook?

Answer: useState is a React Hook that lets function components store state and update the UI when that state changes.

Q2. What does useState return?

Answer: It returns an array with two values: the current state and a setter function for updating it.

Q3. Can we use multiple useState Hooks in one component?

Answer: Yes. A component can declare multiple state variables for different pieces of information, provided the Hooks are called according to the Rules of Hooks.

Q4. Why does React re-render after a state update?

Answer: React uses the updated state to render the component again so the UI can reflect the new value. React may skip rendering work when the next state is identical to the current state according to Object.is.

Q5. What is a functional state update?

Answer: It passes a function to the setter, such as setCount(previous => previous + 1). React uses the pending previous state to calculate the next state.

Q6. Can useState store objects and arrays?

Answer: Yes. When updating them, create a new object or array instead of mutating the existing state value.

Q7. What happens if we call a setter function?

Answer: It requests a state update. The new state is available in a subsequent render; reading the state variable immediately in the same handler still returns the current render's value.

Q8. Can we call useState inside an if statement?

Answer: No. Ordinary Hooks must be called at the top level of a function component or custom Hook, not inside conditions or loops.

Q9. What is lazy initialization?

Answer: It means passing an initializer function, such as useState(createInitialValue), so React can call it to calculate the initial state rather than recalculating it on every render.

Q10. What is the difference between state and props?

Answer: State is managed inside a component using Hooks or other React state mechanisms. Props are values passed to a component by its parent.

22. Quick Revision Checklist

  • Understand the meaning and purpose of state.
  • Know the syntax of the useState Hook.
  • Understand state variables and setter functions.
  • Practice number, string, boolean, object, and array states.
  • Understand controlled inputs and event handlers.
  • Use functional updates when the next value depends on the previous state.
  • Avoid mutating objects and arrays.
  • Follow the Rules of Hooks.
  • Understand why state updates do not immediately change the current render's value.
  • Build a counter, toggle, form, and todo-list project.

23. Conclusion

The useState Hook is one of the most important React Hooks because it enables components to remember changing information and respond to user interactions. By understanding state initialization, setter functions, functional updates, controlled inputs, and immutable updates, developers can build interactive and maintainable React applications.

To continue learning React JS, visit JustAcademy React JS Training Course or register for a React JS course demo.

whatsapp