Skip to content

Commit a334a2c

Browse files
committed
usestate hooks examples
1 parent 0c30347 commit a334a2c

File tree

4 files changed

+183
-0
lines changed

4 files changed

+183
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Example: ControlledFormMinimal
3+
* What: Multi-field controlled form with reset.
4+
* Why: Shows how to manage form state as a single object via useState.
5+
* Concepts: Controlled inputs, updater by key, type-narrowing for selects.
6+
*/
7+
import { useState } from "react";
8+
9+
type Form = { name: string; email: string; role: "user" | "admin" };
10+
11+
export default function ControlledFormMinimal() {
12+
// Store all form fields in a single state object
13+
const initial: Form = { name: "", email: "", role: "user" };
14+
const [form, setForm] = useState<Form>(initial);
15+
16+
// Generic updater function: updates any field by key
17+
// Uses computed property names [key] to dynamically set the field
18+
const update = (key: keyof Form, value: string) => {
19+
setForm(f => ({ ...f, [key]: value }));
20+
};
21+
22+
return (
23+
<form onSubmit={e => e.preventDefault()}>
24+
{/* Controlled input: value from state, updates on change */}
25+
<input
26+
placeholder="name"
27+
value={form.name}
28+
onChange={e => update("name", e.target.value)}
29+
/>
30+
31+
<input
32+
placeholder="email"
33+
value={form.email}
34+
onChange={e => update("email", e.target.value)}
35+
/>
36+
37+
{/* Controlled select: works same as input */}
38+
<select
39+
value={form.role}
40+
onChange={e => update("role", e.target.value)}
41+
>
42+
<option value="user">user</option>
43+
<option value="admin">admin</option>
44+
</select>
45+
46+
{/* Reset form to initial values */}
47+
<button type="button" onClick={() => setForm(initial)}>Reset</button>
48+
49+
{/* Display current form state as JSON */}
50+
<pre>{JSON.stringify(form, null, 2)}</pre>
51+
</form>
52+
);
53+
}
54+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Example: BatchingAndTiming
3+
* What: Observe how React batches state updates across the same tick and microtasks.
4+
* Why: Helps reason about when UI updates happen and why functional updates are safer.
5+
* Concepts: React 18+ automatic batching, microtask (Promise) boundary.
6+
*/
7+
import { useState } from "react";
8+
9+
export default function BatchingAndTiming() {
10+
const [n, setN] = useState(0);
11+
12+
const click = async () => {
13+
// These two updates happen in the same tick - React batches them
14+
// Only ONE re-render happens after both updates complete
15+
setN(v => v + 1); // Update 1: n becomes n+1
16+
setN(v => v + 1); // Update 2: n becomes n+2 (uses result from update 1)
17+
18+
// Wait for next microtask (Promise resolves)
19+
await Promise.resolve();
20+
21+
// Even after microtask boundary, React 18+ still batches this
22+
// Still part of the same event, so batched with the above updates
23+
setN(v => v + 1); // Update 3: n becomes n+3
24+
25+
// Result: UI updates once with final value (n+3)
26+
};
27+
28+
return (
29+
<div>
30+
<p>n = {n}</p>
31+
{/* Click to see batching: all 3 increments happen together */}
32+
<button onClick={click}>Increment 3</button>
33+
</div>
34+
);
35+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Example: UndoRedoMinimal
3+
* What: Basic undo/redo using three pieces of state (past/present/future).
4+
* Why: Shows modeling complex behavior *only with useState* (no reducer).
5+
* Concepts: History stacks, pushing/popping with functional updates.
6+
*/
7+
import { useState } from "react";
8+
9+
export default function UndoRedoMinimal() {
10+
// Three state pieces for undo/redo:
11+
const [past, setPast] = useState<number[]>([]); // Stack of previous values
12+
const [present, setPresent] = useState(0); // Current value
13+
const [future, setFuture] = useState<number[]>([]); // Stack of "undone" values
14+
15+
// Set new value: save current to past, clear future
16+
const set = (val: number) => {
17+
setPast(p => [...p, present]); // Push current value to past stack
18+
setPresent(val); // Set new current value
19+
setFuture([]); // Clear future (can't redo after new change)
20+
};
21+
22+
// Undo: move current to future, pop from past to current
23+
const undo = () => {
24+
setPast(p => {
25+
if (!p.length) return p; // Nothing to undo
26+
27+
const prev = p[p.length - 1]; // Get last past value
28+
setFuture(f => [present, ...f]); // Push current to future stack
29+
setPresent(prev); // Restore previous value
30+
return p.slice(0, -1); // Remove last item from past
31+
});
32+
};
33+
34+
// Redo: move current to past, pop from future to current
35+
const redo = () => {
36+
setFuture(f => {
37+
if (!f.length) return f; // Nothing to redo
38+
39+
const next = f[0]; // Get first future value
40+
setPast(p => [...p, present]); // Push current to past stack
41+
setPresent(next); // Restore next value
42+
return f.slice(1); // Remove first item from future
43+
});
44+
};
45+
46+
return (
47+
<div>
48+
<p>Value: {present}</p>
49+
50+
{/* Change value buttons */}
51+
<button onClick={() => set(present - 1)}>-1</button>
52+
<button onClick={() => set(present + 1)}>+1</button>
53+
54+
{/* Undo/Redo buttons - disabled when stacks are empty */}
55+
<button onClick={undo} disabled={!past.length}>
56+
Undo
57+
</button>
58+
<button onClick={redo} disabled={!future.length}>
59+
Redo
60+
</button>
61+
</div>
62+
);
63+
}
64+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Example: PersistLocalStorage
3+
* What: Persist a piece of state to localStorage using lazy init.
4+
* Why: Demonstrates persistence + correct first-render initialization pattern.
5+
* Concepts: Lazy initializer, side-effect persistence (tiny useEffect), toggles.
6+
*/
7+
import { useEffect, useState } from "react";
8+
9+
export default function PersistLocalStorage() {
10+
// Lazy init: read from localStorage on first render only
11+
// If no saved value exists, default to "light"
12+
const [theme, setTheme] = useState<string>(() =>
13+
localStorage.getItem("theme") || "light"
14+
);
15+
16+
// Save to localStorage whenever theme changes
17+
// This runs after every render where theme is different
18+
useEffect(() => {
19+
localStorage.setItem("theme", theme);
20+
}, [theme]);
21+
22+
return (
23+
<div>
24+
{/* Toggle between light and dark themes */}
25+
<button onClick={() => setTheme(t => (t === "light" ? "dark" : "light"))}>
26+
Toggle theme (current: {theme})
27+
</button>
28+
</div>
29+
);
30+
}

0 commit comments

Comments
 (0)