React useState Hook

The React useState hook lets a function component remember values between renders. When you update state, React re-renders the component with the new value, and the screen updates automatically.

Hooks are special functions whose names start with use. They must be called at the top level of a component, never inside loops, conditions or nested functions.

A Counter with useState

useState(0) returns an array with two items: the current value and a setter function. We destructure them into count and setCount. The 0 is the initial value used on the first render only.

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  );
}
Clicked 0 times
(after 3 clicks)
Clicked 3 times

Updating State Based on the Previous Value

State updates are applied on the next render, so count inside a handler is a snapshot. When the new value depends on the old one, pass a function to the setter. React calls it with the latest value.

function addThree() {
  setCount((c) => c + 1);
  setCount((c) => c + 1);
  setCount((c) => c + 1);
}
// count goes 0 -> 3

function addThreeWrong() {
  setCount(count + 1);
  setCount(count + 1);
  setCount(count + 1);
}
// count goes 0 -> 1
addThree: 3
addThreeWrong: 1

State with Objects

Never change a state object directly. Create a new object with the spread operator, copying the old fields and overriding the ones that change.

const [user, setUser] = useState({ name: 'Sara', age: 25 });

function birthday() {
  setUser({ ...user, age: user.age + 1 });
}
{ name: 'Sara', age: 26 }

State with Arrays

The same rule applies to arrays: use methods that return new arrays instead of push, splice or sort on the original.

  • Add: setItems([...items, newItem])
  • Remove: setItems(items.filter((i) => i.id !== id))
  • Update: setItems(items.map((i) => (i.id === id ? { ...i, done: true } : i)))
  • Sort: setItems([...items].sort(compareFn))

Multiple State Variables

You can call useState as many times as you like. Group values that change together, and keep unrelated ones separate.

function Signup() {
  const [email, setEmail] = useState('');
  const [agreed, setAgreed] = useState(false);
  const [step, setStep] = useState(1);
  // ...
}
(three independent pieces of state)

State Is Private to Each Instance

If you render <Counter /> twice, each copy has its own count. Clicking one does not affect the other. To share state between components, move it up to their closest common parent and pass it down as props, a pattern called lifting state up.

Frequently asked questions

Why is my React state not updating immediately?

The setter schedules a re-render; the variable in the current function keeps its old value. Read the new value on the next render, or use the updater form setX(prev => ...) when you need the latest value.

How do I update an object in React state?

Create a new object: setForm({ ...form, email: value }). Mutating the existing object will not trigger a re-render.

What is the difference between useState and a normal variable?

A normal variable resets on every render and changing it does not update the screen. A state variable is preserved by React between renders, and setting it triggers a re-render.

Can I use useState inside an if statement?

No. Hooks must run in the same order on every render, so call them at the top level of the component, not inside conditions or loops.