State Management

useState

Declares a state variable that triggers re-renders when updated. The most fundamental React hook for managing component-level state.

Signature

TypeScript
const [state, setState] = useState<T>(initialState: T | (() => T))

Parameters

ParameterTypeDescription
initialStateT | () => TThe initial value for the state variable, or a lazy initializer function that returns the initial value.

Return Value

A tuple of [state, setState]. state is the current value. setState is a function that accepts a new value or an updater function (prev => next) and schedules a re-render.

Examples

Basic Counter
import { useState } from 'react';

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={() => setCount(prev => prev - 1)}>Decrement</button>
    </div>
  );
}
Object State
import { useState } from 'react';

function UserForm() {
  const [user, setUser] = useState({ name: '', email: '' });

  const updateField = (field: string, value: string) => {
    setUser(prev => ({ ...prev, [field]: value }));
  };

  return (
    <form>
      <input
        value={user.name}
        onChange={e => updateField('name', e.target.value)}
        placeholder="Name"
      />
      <input
        value={user.email}
        onChange={e => updateField('email', e.target.value)}
        placeholder="Email"
      />
    </form>
  );
}
Lazy Initialization
import { useState } from 'react';

function ExpensiveComponent() {
  // The initializer function only runs on the first render
  const [data, setData] = useState(() => {
    const saved = localStorage.getItem('app-data');
    return saved ? JSON.parse(saved) : { items: [], filter: 'all' };
  });

  const addItem = (item: string) => {
    setData(prev => ({
      ...prev,
      items: [...prev.items, item],
    }));
  };

  return <div>{data.items.length} items loaded</div>;
}

Common Pitfalls

!

Mutating state directly instead of creating a new reference — always spread objects/arrays to create new copies.

!

Calling setState in a loop without using the updater function form, which can lead to stale closures.

!

Using an expensive computation as initialState without wrapping it in a function — pass () => expensiveCompute() instead.

!

Expecting state updates to be synchronous — React batches updates and the new value is only available on the next render.

Understanding useState

useState is the cornerstone of React's hook-based state management. Introduced in React 16.8, it allows function components to hold and update local state without converting to class components. When you call useState, React allocates a slot in the component's fiber node to persist the value across re-renders.

The setter function returned by useState can accept either a direct value or an updater function. The updater form (prev => next) is essential when the new state depends on the previous state, especially inside event handlers or effects where closures might capture stale values. React batches multiple setState calls within the same event handler into a single re-render for performance.

State updates in React are immutable by convention. For objects and arrays, you must create new references for React to detect changes. Directly mutating an object property and passing the same reference to setState will not trigger a re-render. This immutability pattern is what enables React's efficient reconciliation algorithm.

Lazy initialization is an important optimization. If your initial state requires an expensive computation — such as parsing localStorage, filtering a large dataset, or running a complex calculation — wrap it in a function. React will only call this initializer on the first render, skipping it entirely on subsequent re-renders. This can significantly improve mount performance for components that initialize with heavy data processing.

Related Hooks

More State Management Hooks

Explore All React Hooks

Browse our complete reference of 19 React hooks with signatures, examples, pitfalls, and in-depth explanations.