DG
DevGuide
Run Code
Home/React/useState
⚛ React2 / 4

useState

📌 WHAT

useState is a React Hook that lets a component declare and update its own internal data. When state changes, React automatically re-renders the component with the new data.

💡 WHY

Without state, UIs are static. State enables interactivity — counters, form inputs, toggle menus, fetched data, loading states.

⏰ WHEN / WHERE

Any time data inside a component changes over time and the UI should reflect those changes: user input, toggles, counters, async data, error states.

🔧 HOW

Call useState(initialValue) inside your component. It returns [currentValue, setterFunction]. ALWAYS use the setter to update — never mutate state directly.

📚Key Terms

Re-render

— React calls your component function again with new state values and updates the DOM

Setter function

— The second item from useState — call it to update state and trigger re-render

Functional update

— Pass a function to setter: setState(prev => prev + 1). Use when new state depends on old state

State batching

— React groups multiple setState calls into one re-render for performance

Code Examples

#1useState fundamentals

useState fundamentals
tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
"use client"; // Must be client component for hooks
import { useState } from "react";
// 1. Simple counter
function Counter() {
// [current value, function to update it]
const [count, setCount] = useState(0); // 0 = initial value
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
// 2. Toggle state
function Toggle() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(prev => !prev)}>
{isOpen ? "Close" : "Open"} Menu
</button>
{isOpen && <nav>Menu content here</nav>}
</div>
);
}
// 3. Object state — ALWAYS spread to update
function UserForm() {
const [user, setUser] = useState({
name: "",
email: "",
role: "user",
});
// ✅ Correct — spread existing state, override specific field
const updateField = (field: string, value: string) => {
setUser(prev => ({ ...prev, [field]: value }));
};
// ❌ Wrong — mutating state directly
// user.name = "Ali"; // This does NOT cause a re-render!
return (
<form>
<input
value={user.name}
onChange={(e) => updateField("name", e.target.value)}
/>
<input
value={user.email}
onChange={(e) => updateField("email", e.target.value)}
/>
</form>
);
}

Practice This Concept

Open the playground, paste any example, and experiment. The best way to learn is by breaking things.

Open in Playground