State with useState
State is data a component remembers and can change. When state changes, React re-renders the component so the screen matches the new data.
React (JSX)
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h2>{count}</h2>
<button onClick={() => setCount(count + 1)}>+1</button>{" "}
<button onClick={() => setCount(count - 1)}>−1</button>{" "}
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
function App() {
return <Counter />;
}useState(0) returns two things:
count: the current value (starting at 0),setCount: a function to change it.
Calling setCount stores the new value and tells React to re-render.
Why not a normal variable?
A normal variable is recreated, back at its starting value, every time the function runs, and changing it doesn't trigger a re-render. State survives between renders and does trigger them.
Several pieces of state
React (JSX)
import { useState } from "react";
function App() {
const [name, setName] = useState("");
const [likes, setLikes] = useState(0);
return (
<div>
<input value={name} onChange={(e) => setName(e.target.value)} placeholder="Your name" />
<p>Hello, {name || "stranger"}!</p>
<button onClick={() => setLikes(likes + 1)}>❤️ {likes}</button>
</div>
);
}Updating from the previous value
When the new state depends on the old one, pass a function. React gives it the latest value, which matters when updates happen quickly:
React (JSX)
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
function addThree() {
setCount((c) => c + 1);
setCount((c) => c + 1);
setCount((c) => c + 1);
}
return <button onClick={addThree}>Add 3 (now {count})</button>;
}With setCount(count + 1) three times, you'd only add 1, because all three calls would see the same old count.
Arrays and objects in state
Never change state directly; create a new array or object:
React (JSX)
import { useState } from "react";
function App() {
const [items, setItems] = useState(["Learn JSX"]);
const [text, setText] = useState("");
function add() {
if (!text.trim()) return;
setItems([...items, text]); // a NEW array
setText("");
}
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} placeholder="New task" />
<button onClick={add}>Add</button>
<ul>{items.map((item, i) => <li key={i}>{item}</li>)}</ul>
</div>
);
}Finished this lesson?Mark it complete to earn +20 XP and move your progress on.