State with useState

Props flow into a component from the outside, but a component often needs to track its own data that changes over time — a counter's current count, whether a menu is open, what someone has typed into a field. That's what state is for, and useState is how you add it to a function component.

Declaring state

useState(initialValue) returns a pair: the current value, and a function to update it. The square-bracket syntax is array destructuring, naming both parts at once:

JSX Counter.jsx
import { useState } from "react";

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}
Rendered output
"Count: 0" and a "+1" button. Each click re-renders
the component with count increased by one:
"Count: 1", "Count: 2", and so on.

count is the current value (starting at 0, the argument passed to useState). setCount is the only correct way to change it — calling setCount(count + 1) tells React "re-render this component, and this time count should be this new value." Writing count = count + 1 directly would not work; React has no way to know the value changed.

State is private to each component instance

Every time you render a component, its state is independent from any other instance of the same component:

JSX App.jsx
function App() {
  return (
    <>
      <Counter />
      <Counter />
    </>
  );
}
Rendered output
Two separate counters, each starting at 0. Clicking
the first one's button only changes that counter —
the second stays at whatever it was.
Note: state updates are asynchronous and batched — calling setCount doesn't change count immediately in the same line of code that called it. setCount(count + 1); console.log(count); logs the old value, because count in that scope was already fixed when the component last rendered. The new value only shows up on the next render.