Basic Usage
Basic Usage
Syntax
const [state, setState] = useState(initialValue);
state: Current state valuesetState: Function to update stateinitialValue: Initial state value
Simple Example
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={() => setCount(count - 1)}>Decrement</button>
</div>
);
}
String State
function NameInput() {
const [name, setName] = useState("");
return (
<div>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<p>Hello, {name || "Stranger"}!</p>
</div>
);
}
Boolean State
function Toggle() {
const [isOn, setIsOn] = useState(false);
return (
<div>
<button onClick={() => setIsOn(!isOn)}>
{isOn ? "ON" : "OFF"}
</button>
</div>
);
}
Object State
function UserForm() {
const [user, setUser] = useState({
name: "",
email: "",
age: 0
});
const updateField = (field, value) => {
setUser((prev) => ({ ...prev, [field]: value }));
};
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>
);
}
Lazy Initialization
Lazy Initialization
The Problem
// Bad: Expensive computation on every render
function ExpensiveComponent() {
const [data, setData] = useState(computeExpensiveValue()); // Runs every render
}
The Solution
// Good: Lazy initialization - only runs once
function ExpensiveComponent() {
const [data, setData] = useState(() => computeExpensiveValue());
}
When to Use
- Expensive computations
- Large data structures
- Reading from localStorage
- Initializing complex objects
Examples
// localStorage
function App() {
const [theme, setTheme] = useState(() => {
return localStorage.getItem("theme") || "light";
});
}
// Complex calculation
function App() {
const [fibonacci, setFibonacci] = useState(() => {
return calculateFibonacci(100);
});
}
// Large array
function App() {
const [items, setItems] = useState(() => {
return generateLargeArray(10000);
});
}
Functional Updates
Functional Updates
The Problem
function Counter() {
const [count, setCount] = useState(0);
const incrementThree = () => {
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
// Only adds 1! count is still 0 in all three calls
};
}
The Solution
function Counter() {
const [count, setCount] = useState(0);
const incrementThree = () => {
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
// Adds 3! Each update uses the latest value
};
}
When to Use
- New state depends on old state
- Multiple updates in same handler
- Avoiding stale closures
Examples
// Toggle
const toggle = () => setOn((prev) => !prev);
// Increment
const increment = () => setCount((prev) => prev + 1);
// Add to array
const addItem = (item) => setItems((prev) => [...prev, item]);
// Remove from array
const removeItem = (id) => setItems((prev) => prev.filter((item) => item.id !== id));
// Update object
const updateUser = (updates) => setUser((prev) => ({ ...prev, ...updates }));
Quiz
1. What does useState return (specific to usestate)?
2. When should you use lazy initialization?
3. What is a functional update?
4. Why use functional updates?
Flashcards
Question
What does useState return?
Click to reveal answer
Answer
An array with [state, setState]
Question
What is lazy initialization?
Click to reveal answer
Answer
Passing a function to useState that computes the initial value
Question
When to use functional updates?
Click to reveal answer
Answer
When new state depends on old state
Question
How do you update object state?
Click to reveal answer
Answer
Spread previous state and override: { ...prev, field: value }
Revision Notes
Key Takeaways
- 1. useState returns [state, setState]
- 2. Use lazy initialization for expensive computations
- 3. Use functional updates when new state depends on old
- 4. Always create new objects/arrays for state updates
- 5. Multiple setStates in same handler are batched
Interview Tips
- • Explain lazy initialization vs immediate initialization
- • Show functional update patterns
- • Demonstrate immutable state updates
Cheat Sheet
Cheat Sheet
Basic Usage
const [count, setCount] = useState(0);
setCount(count + 1);
Lazy Initialization
const [data, setData] = useState(() => expensiveCalc());
Functional Update
setCount(prev => prev + 1);
Object State
const [user, setUser] = useState({ name: "", age: 0 });
setUser(prev => ({ ...prev, name: "Alice" }));
Array State
const [items, setItems] = useState([]);
setItems(prev => [...prev, newItem]);
setItems(prev => prev.filter(i => i.id !== id));