useState

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

React components are just functions. Without `useState`, variables would reset every time the function runs. State gives your component a memory.

The Memory Problem

Regular variables are forgetful. When a component re-renders (runs again), all its local variables reset. `useState` is how we give components a permanent memory.

Persistence

React keeps the state alive outside your component function. When you call `setState`, React updates the value in its internal storage and triggers a re-render.

Replacing Values

For primitives (strings, numbers, booleans), `setState` simply discards the old value and replaces it with the new one. It's a complete swap.

Objects & Arrays

Unlike class components, `useState` does NOT automatically merge objects. You must manually copy the old properties using the spread operator `...prev`.

Automatic Batching

React is smart. It groups multiple state updates into a single re-render for better performance. This is why you shouldn't rely on the state value immediately after setting it.

Anatomy of useState

It returns an array with two items: the current state value, and a function to update it.

Counter.tsx
import { useState } from 'react';

function Counter() {
  // 1. Declare state variable "count"
  // 2. Initialize it to 0
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  );
}
Basic Counter Example

Functional Updates

If your new state depends on the old state, always use the functional form. This ensures you're working with the latest value, especially during batching.

SafeUpdate.tsx
// ❌ Potentially Buggy (uses stale 'count')
setCount(count + 1);
setCount(count + 1); // might not increment twice!

// ✅ Safe & Reliable (uses 'prev')
setCount(prev => prev + 1);
setCount(prev => prev + 1); // Guaranteed to increment twice
Use the callback form for dependent updates!

Handling Objects

Never mutate state directly. Always create a new object and copy the old properties first.

UserObject.tsx
const [user, setUser] = useState({ name: 'Alice', age: 25 });

// ❌ BAD: Mutating state directly
user.age = 26; // React won't know!

// ❌ BAD: Overwriting the object
setUser({ age: 26 }); // Lost the name!

// ✅ GOOD: Spreading properties
setUser(prev => ({ 
  ...prev, // Copy name: 'Alice'
  age: 26  // Overwrite age
}));
Spread Operator Pattern

Next: useEffect

Now that your component has memory, let's learn how to make it *do things* (side effects) like fetching data.

Learn useEffect
AlgoAnimator: Interactive Data Structures