State Pitfalls

Mistakes Every React Developer Makes Exactly Once

State Pitfalls

The handful of state mistakes that bite everyone — collected so you can recognize them in the wild.

4 min read Level 2/5 #react#state#pitfalls
What you'll learn
  • Spot common state bugs in your own code
  • Know the right fix for each

A grab-bag of the most common state mistakes. None of them are deep — just easy to make and easy to fix once you’ve seen the pattern.

1. Reading State Right After Setting It

// ✗
setCount(count + 1);
console.log(count);   // OLD value

State updates queue a re-render. count in this render is fixed. If you need the new value in this turn, compute it locally:

const next = count + 1;
setCount(next);
console.log(next);

2. Storing Derived Values

// ✗ Two state slots, easy to drift
const [items, setItems] = useState([]);
const [count, setCount] = useState(0);

// ✓ Derive
const count = items.length;

3. Mutating Instead of Replacing

// ✗
items.push(newItem);
setItems(items);

// ✓
setItems([...items, newItem]);

4. Using Index as a Key in a Reorderable List

// ✗ Looks fine until you reorder
{items.map((item, i) => <Row key={i} item={item} />)}

// ✓
{items.map(item => <Row key={item.id} item={item} />)}

5. Setting State in the Render Body

// ✗ Infinite loop — every render queues another render
function Bad() {
  const [n, setN] = useState(0);
  setN(n + 1);
  return <p>{n}</p>;
}

State updates belong in event handlers, effects, or other reactions to something happening — never in the render body directly. (There’s a narrow exception with stale state synchronization, but treat it as “never” for now.)

6. The Falsy 0 in &&

// ✗ Renders the literal "0" when count is 0
{count && <Badge>{count}</Badge>}

// ✓
{count > 0 && <Badge>{count}</Badge>}

7. Updater Form For Dependent Updates

// ✗ Three setters, same snapshot → final value is +1
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);

// ✓ Updater form stacks correctly → +3
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);

8. Object Identity Is What Matters

// Re-renders, even though the contents look the same
setUser({ ...user });

React compares references. A new object is a new reference, even if every field is identical.

Up Next

Time for the second-most-used hook: side effects.

useEffect →