Prerequisites

Before working with useState, it is helpful to understand:

  • JavaScript fundamentals
  • ES6 syntax, including destructuring and the spread operator
  • React functional components
  • JSX
  • Basic event handling in React

What Is useState?

useState is a React Hook that lets a functional component store a value and update that value over time. When the setter function is used, React schedules a re-render so the component can display the latest state.

The basic syntax is:

JavaScript

const [state, setState] = useState(initialValue);

 

For example:

JavaScript

import { useState } from "react";

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

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={() => setCount(count + 1)}>
        Increase
      </button>
    </div>
  );
}

 

In this example:

  • count is the current state value.
  • setCount is the setter function used to request a state update.
  • 0 is the initial value.
  • Each click requests a new count value, and React re-renders the component with the updated state.

Why Is useState Important?

A React application frequently needs to respond to user actions. A user might enter a name, add a record, search for information, select a filter, or show and hide part of the interface. State gives the component a way to remember those changing values.

Common use cases include:

  • Form inputs
  • Counters and numeric values
  • Lists of data
  • Search fields
  • Filters
  • Toggle buttons
  • Edit modes
  • Showing or hiding UI elements

How State Updates Flow Through a React Component

A simplified state-update flow looks like this:

  1. The user interacts with the UI.
  2. An event handler runs.
  3. The event handler calls a state setter.
  4. React schedules a re-render.
  5. The component renders with the new state.
  6. The UI reflects the updated value.

Important: calling a state setter does not immediately change the current state variable inside the running event handler. The updated value is available during the next render.

Managing Arrays with useState

State can hold arrays and objects, not just strings and numbers. For example, a dashboard might maintain a list of records that users can add to or remove from.

An array can be initialized like this:

JavaScript

const [students, setStudents] = useState([
  { id: 1, name: "Akshu", course: "CSE", age: 20 },
  { id: 2, name: "Rahul", course: "IT", age: 21 }
]);

 

Here, students contains the current array and setStudents is used to request changes to that array. The same pattern applies to dashboards, inventory lists, task lists, and other data-driven interfaces.

Adding Data to State

When adding an item to an array in state, create a new array rather than modifying the existing array directly.

JavaScript

const newStudent = {
  id: Date.now(),
  name: "Priya",
  course: "CSE",
  age: 20
};

setStudents((prevStudents) => [
  ...prevStudents,
  newStudent
]);

 

The spread operator creates a new array containing the previous items and the new item. The functional update form is especially useful when the next state depends on the previous state.

Removing Data from State

The filter() method can create a new array without the item that should be removed.

JavaScript

setStudents((prevStudents) =>
  prevStudents.filter(
    (student) => student.id !== 2
  )
);

 

This returns every student except the one with ID 2 and avoids directly mutating the existing state array.

Managing Form Inputs

Forms are one of the most common use cases for useState. Each input can be connected to a state value, creating a controlled input.

JavaScript

const [name, setName] = useState("");
const [course, setCourse] = useState("");
const [age, setAge] = useState("");

 

A state value can then be connected to an input:

JavaScript

<input
  type="text"
  value={name}
  onChange={(e) => setName(e.target.value)}
  placeholder="Student Name"
/>

 

Whenever the user changes the input, the event handler calls setName(). React then renders the input with the latest state value.

useState and Search Functionality

A search field can also be managed with state:

JavaScript

const [search, setSearch] = useState("");

<input
  type="text"
  value={search}
  onChange={(e) => setSearch(e.target.value)}
  placeholder="Search students"
/>

 

The search value can then be used to calculate a filtered list:

JavaScript

const filteredStudents = students.filter((student) =>
  student.name
    .toLowerCase()
    .includes(search.toLowerCase())
);

 

Because the component re-renders when search changes, the filtered result can update immediately as the user types.

Common Mistakes to Avoid

1. Directly Modifying State

Avoid mutating an existing array:

JavaScript

students.push(newStudent);

 

Instead, create a new array and update state:

JavaScript

setStudents((prevStudents) => [
  ...prevStudents,
  newStudent
]);

 

2. Using Unclear State Names

Prefer names that describe the value and its setter:

JavaScript

const [search, setSearch] = useState("");

 

Avoid unclear names such as:

JavaScript

const [x, setX] = useState("");

 

Clear names make code easier to read, review, debug, and maintain.

3. Forgetting to Import useState

The Hook must be imported before it is used:

JavaScript

import { useState } from "react";

 

4. Using the Current Value When the Next Value Depends on Previous State

When the next state depends on the previous state, prefer the functional update form. This is especially useful when multiple updates may be scheduled together.

JavaScript

setCount((previousCount) => previousCount + 1);

 

Best Practices for Using useState

  • Use meaningful names for state variables and setter functions.
  • Do not directly mutate arrays or objects stored in state.
  • Use the functional update form when the next state depends on the previous state.
  • Keep state focused on values that actually change over time.
  • Keep related state values organized and avoid unnecessary duplication.
  • Avoid storing values in state when they can be calculated from existing state or props.
  • Keep state local to the component when it is only needed there; use broader state management only when shared state is actually required.
  • Keep event handlers focused so state transitions remain easy to understand.

When Should You Use useState?

useState is a good choice when a component needs to remember a value that changes as users interact with the interface. Typical examples include:

  • A form field that changes as the user types
  • A selected tab or filter
  • An expanded or collapsed section
  • A list that users can add to or remove from
  • A search query and its derived results
  • A counter or other local UI value

When useState Is Not Enough

useState is component-level state. If many unrelated components need to read and update the same state, lifting state to a common parent, using Context, or adopting a dedicated state-management library may be more appropriate.

The goal is not to move every value into global state. Keep state as close as practical to the components that own and use it.

Real-World Applications

  • Dashboards — managing filters, selections, and interactive data
  • E-commerce applications — managing cart items, quantities, and product filters
  • Task applications — adding, editing, completing, and removing tasks
  • Contact forms — managing user-entered values and validation state
  • Search interfaces — handling search queries and filtered results
  • Administrative applications — managing selected records, edit modes, and form values

Key Takeaways

  • useState lets functional components remember and update changing values.
  • It returns the current state value and a setter function.
  • State updates cause React to render the component again with the new state.
  • Arrays and objects in state should be updated without directly mutating the existing value.
  • Functional state updates are useful when the next value depends on the previous value.
  • Not every calculated value needs to be stored in state.
  • useState is ideal for local component state; shared application state may require a different approach.

Conclusion

useState is one of the most important concepts for developers learning React. It provides a simple way for components to remember changing values and keep the user interface synchronized with user interactions.

By applying useState to forms, lists, search, filters, and other interactive features, developers can understand the core relationship between events, state updates, rendering, and UI changes.

Once these fundamentals are clear, concepts such as useEffect, useReducer, Context, and more advanced state-management patterns become easier to understand.