iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

useState

The useState hook adds local state to a function component. It returns the current value and a setter; calling the setter triggers a re-render with the new value.

Counter, form field, lazy init

EXAMPLE
import { useState } from 'react';

// 1) Basic counter
function Counter() {
    const [count, setCount] = useState(0);
    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>+1</button>
            <button onClick={() => setCount(c => c + 1)}>+1 (functional)</button>
        </div>
    );
}

// 2) Functional updater — when next state depends on previous
function RapidClicks() {
    const [n, setN] = useState(0);
    return (
        <button onClick={() => {
            setN(c => c + 1);   // safely batched
            setN(c => c + 1);   // +2 total, not +1
        }}>+2</button>
    );
}

// 3) Form field — single source of truth
function NameForm() {
    const [name, setName] = useState('');
    return (
        <input value={name} onChange={(e) => setName(e.target.value)} />
    );
}

// 4) Object state — spread to preserve other fields
function Profile() {
    const [user, setUser] = useState({ name: '', email: '', age: 0 });
    return (
        <input
            value={user.email}
            onChange={(e) => setUser({ ...user, email: e.target.value })}
        />
    );
}

// 5) Lazy initial state — expensive compute runs ONCE
function Tree() {
    const [tree, setTree] = useState(() => buildHugeTree());   // function, not value
    // buildHugeTree() runs on mount, not on every render
}

// 6) Multiple states — usually cleaner than one big object
function LoginForm() {
    const [email, setEmail]       = useState('');
    const [password, setPassword] = useState('');
    const [busy, setBusy]         = useState(false);
}

// 7) State is replaced, not merged — different from class setState
const [pos, setPos] = useState({ x: 0, y: 0 });
setPos({ x: 10 });        // y is now undefined!
setPos((p) => ({ ...p, x: 10 }));   // correct

Why it matters

Use a functional updater (setN(c => c + 1)) any time the new value depends on the previous one. It survives React batching and any race against stale closures.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
const [count, setCount] = useState(0);
const increment = () => setCount(c => c + 1);
Try it Yourself »

Discussion

Loading…