Skip to content

React useState Explained for Beginners

October 27, 2026 · 2 min read

Use useState when a component needs to remember a value and update the screen when it changes. A plain variable can't do that, because React doesn't know it changed and runs your function from the top on every render.

A quantity counter, two ways

This component has a plain variable and a state variable side by side:

import { useState } from "react";

export default function Counter() {
  let plain = 0;
  const [qty, setQty] = useState(1);

  return (
    <div>
      <button onClick={() => { plain = plain + 1; console.log("plain is now", plain); }}>
        Plain: {plain}
      </button>
      <button onClick={() => setQty(qty + 1)}>Qty: {qty}</button>
    </div>
  );
}

Click Plain twice, then click Qty twice. The Console prints:

plain is now 1
plain is now 2

The buttons end up like this:

Plain: 0 | Qty: 3

The variable really changed (1, then 2), but the "Plain" button never left 0. The "Qty" button went from 1 to 3.

What is happening

  • useState(1) returns a pair: the current value (qty) and a setter function (setQty). The 1 is the initial value, used only on the first render.
  • Calling setQty(qty + 1) stores the new value and asks React to render the component again. The new render gets the new qty.
  • plain is recreated as 0 on every render, because a render is just a call to your function. Even when you change it, React isn't told, so nothing re-renders. And if a render did happen, let plain = 0 would run again and wipe the change.

State is data a component remembers between renders. React keeps it outside your function and hands it back each time.

Common mistake

Calling the setter instead of passing it:

<button onClick={setQty(qty + 1)}>Qty: {qty}</button>

This runs setQty during the render, which triggers another render, forever. React stops it with "Too many re-renders". Fix it by passing a function that React calls on click:

<button onClick={() => setQty(qty + 1)}>Qty: {qty}</button>

Also don't write qty++ or qty = qty + 1. Always go through the setter.

Takeaway

If a value should show on screen and change over time, put it in useState and change it only with the setter. A normal variable resets on every render.

More on Web Development