Skip to content

React Tutorial State and Events

The useState Hook Explained with Examples

Lesson 44 of 156 2 min read By Deepak Paswan Updated Oct 10, 2026

Runnable lesson · press Try it on the examples to edit and run them here.

useState is the first hook most people learn, and the one you will use most. A hook is a special function whose name starts with use that lets a function component use a React feature: state, effects, context and more.

Syntax

App.jsx
JSX
const [value, setValue] = useState(initialValue);
  • useState(initialValue) returns an array of two items.
  • The first item is the current state; the second is the function that updates it.
  • You choose the names with array destructuring. The convention is thing and setThing.
App.jsx
JSX
function App() {
  const [name, setName] = React.useState("Ada");

  return (
    <div>
      <p>Hello, {name}</p>
      <button onClick={() => setName("Grace")}>Rename</button>
    </div>
  );
}

If array destructuring is new to you, see Array Destructuring.

Any type of value

State can hold any JavaScript value:

App.jsx
JSX
function App() {
  const [name, setName] = React.useState("Ada");           // string
  const [age, setAge] = React.useState(36);                // number
  const [admin, setAdmin] = React.useState(true);          // boolean
  const [skills, setSkills] = React.useState(["JS", "CSS"]); // array

  function changeAll() {
    setName("Grace");
    setAge(85);
    setAdmin(false);
    setSkills([...skills, "COBOL"]);
  }

  return (
    <div>
      <p>{name}, {age}, {String(admin)}, {skills.length} skills</p>
      <button onClick={changeAll}>Change all</button>
    </div>
  );
}

For objects and arrays you must always replace the value with a new one rather than change it. That is covered in Updating Objects in State and Updating Arrays in State.

The initial value is used only once

useState(0) uses 0 only on the first render. On later renders React ignores the argument and gives you the current state.

The lazy initializer

If the initial value is expensive to compute (reading and parsing data, a big calculation), pass a function. React calls it only on the first render:

App.jsx
JSX
function loadItems() {
  console.log("loadItems ran");
  return ["a", "b", "c"];
}

function App() {
  // loadItems() would run on EVERY render; the function form runs only once
  const [items] = React.useState(loadItems);
  const [n, setN] = React.useState(0);

  return (
    <div>
      <p>Items: {items.length}</p>
      <button onClick={() => setN(n + 1)}>Re-render ({n})</button>
    </div>
  );
}

Click the button a few times and look at the console: loadItems ran appears only once. Note that you pass the function itself (loadItems), not a call (loadItems()).

Rules for hooks

Hooks must be called in the same order on every render. So:

  1. Call hooks at the top level of a component or custom hook.
  2. Never call them inside conditions, loops or nested functions.
  3. Call them only from React function components or custom hooks.

Rules of Hooks explains why, and the Vite template has a lint rule that catches mistakes.

A toggle and a counter

Two small patterns that appear everywhere:

App.jsx
JSX
function App() {
  const [open, setOpen] = React.useState(false);
  return (
    <div>
      <button onClick={() => setOpen(!open)}>Toggle menu</button>
      <p>Menu is {open ? "open" : "closed"}</p>
    </div>
  );
}

Common mistakes

  • Changing state directly: count = count + 1 or count++ does nothing. Always call the setter.
  • Calling the setter during rendering (setCount(1) in the body of the component) causes an infinite loop. Call it in event handlers or effects.
  • Expecting the new value right after calling the setter. The variable still holds the old value in that function. See State as a Snapshot.
  • Storing too much. Do not store anything you can compute.

Key points

  • const [value, setValue] = useState(initial) creates state; call the setter to change it.
  • The initial value is used once; pass a function for expensive initial values.
  • Call hooks at the top level, never conditionally.