useState

Give a Component Memory

useState

`useState` lets a component remember a value across renders. Call the setter, React re-renders with the new value.

5 min read Level 2/5 #react#hooks#useState
What you'll learn
  • Declare and read state with `useState`
  • Update state and trigger a re-render
  • Initialize state from a function for expensive setup

A component re-runs every time it renders. Local let variables reset every time. useState gives a component a value that survives across renders.

The Shape

import { useState } from "react";

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

  return (
    <button onClick={() => setCount(count + 1)}>
      Clicks: {count}
    </button>
  );
}

useState(initial) returns a tuple:

  • count — the current value
  • setCount — a function to change it

Naming convention: [thing, setThing].

How a Render Happens

  1. Component runs, useState(0) returns [0, setCount]
  2. React renders <button>Clicks: 0</button>
  3. User clicks → handler runs → setCount(1)
  4. React schedules a re-render of Counter
  5. Component runs again, useState returns [1, setCount]
  6. React updates the DOM to show “Clicks: 1”

The state belongs to React, not to your function. Your function just asks for it on each run.

State Types

State can hold any JS value — strings, numbers, booleans, arrays, objects.

const [name, setName] = useState("");
const [items, setItems] = useState([]);
const [user, setUser] = useState({ id: 0, name: "" });
const [open, setOpen] = useState(false);

Setting the Same Value Does Nothing

If you call setCount(count) with the same value, React skips the re-render (using Object.is to compare).

setCount(0);  // count is already 0 → no re-render

For objects and arrays, “same value” means same reference. A new object with the same shape is a different value:

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

Lazy Initialization

If computing the initial value is expensive, pass a function:

const [parsed, setParsed] = useState(() => JSON.parse(localStorage.getItem("data") || "{}"));

The function runs only on the first render. Without the wrapper, the parse would run every render and be thrown away (wasted work).

Multiple State Variables

A component can have as many useState calls as you want. Keep unrelated state in separate variables:

function ProfileForm() {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [age, setAge] = useState(0);

  return ( /* ... */ );
}

When several values change together, a single object is sometimes cleaner — but flat variables are usually easier.

Up Next

State updates have a couple of subtleties. Time to look at them.

State Updates →