React useState Hook

Manage local component state, functional updates, lazy initial state, and immutable updates with useState.

TL;DR

  1. Store interactive component values across renders using the useState hook.
  2. Destructure current state and its dedicated setter dispatch function.
  3. Queue sequential updates reliably by providing an updater callback function.

Basic State Declaration

    Primitive State

    Declare a boolean or numeric value with initial default.

    import { useState } from 'react';
    
    export function Counter() {
      const [count, setCount] = useState(0);
      const inc = () => setCount(count + 1);
      return <Button onClick={inc}>{count}</Button>;
    }
    String Input State

    Track text input values synchronized with DOM events.

    const [name, setName] = useState('');
    <InputBase
      value={name}
      onChange={(e) => setName(e.target.value)}
    />
    Boolean Toggle

    Invert boolean state with concise negation logic.

    const [isOpen, setIsOpen] = useState(false);
    const toggle = () => setIsOpen((prev) => !prev);

Functional Updates

    Sequential Increments

    Queue multiple consecutive updates safely without race bugs.

    function incrementThreeTimes() {
      setCount((c) => c + 1);
      setCount((c) => c + 1);
      setCount((c) => c + 1);
    }
    Async Callback State

    Safely read latest state inside delayed timeouts.

    setTimeout(() => {
      setScore((prev) => prev + 10);
    }, 1000);
    Lazy Initialization

    Execute slow computation only during the initial mount.

    const [data] = useState(() => {
      const raw = localStorage.getItem('key');
      return JSON.parse(raw ?? '{}');
    });

Updating Objects and Arrays

    Object Field Spread

    Spread existing object keys and override targeted property.

    const [user, setUser] = useState({ name: '', age: 0 });
    setUser((prev) => ({ ...prev, name: 'Maya' }));
    Append Array Item

    Create a new array copy appending the new item.

    const [items, setItems] = useState<string[]>([]);
    setItems((prev) => [...prev, 'New Item']);
    Remove Array Item

    Filter out deleted element by matching identifier.

    const remove = (id: string) =>
      setList((prev) => prev.filter((it) => it.id !== id));

State Architecture Best Practices

    Avoid Redundant State

    Derive computed values during render instead of storing state.

    const [items, setItems] = useState<Item[]>([]);
    // Computed dynamically on render
    const total = items.reduce((s, i) => s + i.price, 0);
    Group Related Fields

    Combine properties that always change together into an object.

    const [position, setPosition] = useState({
      x: 0,
      y: 0,
    });
    Reset State via Key

    Pass a different key prop to unmount and reset state cleanly.

    <UserEditor key={userId} userId={userId} />

Tips

  1. Pass a function into useState(() => calc()) to evaluate expensive initial state computations only once on mount.
  2. Always create new object or array references when updating state with ...spread operators rather than modifying variables.

Warnings

  1. Never mutate state directly because React strictly relies on shallow reference inequality checks to trigger component re-renders.
  2. Remember that state setter calls are asynchronous, so reading state immediately after invoking its setter yields the old snapshot.

In Practice

FAQ