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 }));
Practice Problems
Create a reusable React component implementing useState. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for useState using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize useState for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. What does useState return?
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 }
Question
What is useState?
Click to reveal answer
Answer
useState is a key concept in frontend development.
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));