# useState and Event Handlers — React

Source: https://www.skillbyai.com/en/react/s-usestate

> Remembering values between renders.

## State plus a setter

`useState(initial)` returns the current value and a setter. Calling the setter schedules a **re-render** with the new value; the component function runs again and returns updated JSX. Event handlers are passed as props such as `onClick` and `onChange`. Hooks must be called at the top level of a component, in the same order every render, never inside conditions or loops. State is local to each component instance.

## Data that changes over time

State drives re-renders; updates are batched and must be immutable.

![Four ideas: useState, batching, immutability, lifting state.](assets/figures/react/section-3-map.svg) — Figure 3.1 — useState, batching, immutability and lifting state.

## A counter clicked twice, run

I ran this with React 19.3 and react-dom 19.3 on Node.js 22, compiling JSX with esbuild 0.28. Browser-style examples use jsdom 29 as a fake DOM (imported from a small setup-dom.mjs file) and act() to apply updates. The button starts at "Clicked 0 times"; after two clicks, React re-renders and the text reads "Clicked 2 times".

```jsx
import "./setup-dom.mjs";   // test setup: jsdom provides a browser-like DOM in Node
import { useState, act } from "react";
import { createRoot } from "react-dom/client";

function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Clicked {count} times</button>;
}
const root = createRoot(document.getElementById("root"));
await act(() => root.render(<Counter />));
const button = document.querySelector("button");
console.log(button.textContent);
await act(() => button.click());
await act(() => button.click());
console.log(button.textContent);
```

Output:

```
Clicked 0 times
Clicked 2 times
```

## Keep state minimal

Store only what cannot be computed from props or other state; derive the rest during rendering.

**Quiz:** Where can hooks like useState be called?

- [x] At the top level of a component or custom hook, never inside conditions or loops
- [ ] Anywhere, including inside if statements
- [ ] Only inside event handlers
- [ ] Only in class components

*Answer:* At the top level of a component or custom hook, never inside conditions or loops. The rules of hooks keep call order stable.
