useState manages local state in functional components, returning a value and setter function. useEffect handles side effects (data fetching, subscriptions, DOM manipulation) and runs after render. The dependency array controls when effects re-run.
useState:
useEffect:
function Counter() {
// Basic usage
const [count, setCount] = useState(0);
// Lazy initialization (expensive computation)
const [data, setData] = useState(() => {
return computeExpensiveInitialValue();
});
// Object state
const [form, setForm] = useState({ name: '', email: '' });
const updateField = (field, value) => {
setForm(prev => ({ ...prev, [field]: value }));
};
// Functional updates (when new state depends on previous)
const increment = () => {
setCount(prev => prev + 1); // Always uses latest value
};
// Multiple rapid updates
const incrementThree = () => {
// Wrong: all use same stale value
// setCount(count + 1); setCount(count + 1); setCount(count + 1);
// Correct: each uses updated value
setCount(c => c + 1);
setCount(c => c + 1);
setCount(c => c + 1);
};
return <button onClick={increment}>{count}</button>;
}