Event handler capture closure — count được "đóng băng" ở giá trị render hiện tại.
Ba lần setCount(count + 1) đều dùng cùng giá trị cũ → React batch lại, kết quả chỉ +1.
jsx
const [count, setCount] = useState(0)
const handleClick = () => {
// ❌ Direct: closure capture count=0 → 3 lần đều set thành 1
setCount(count + 1)
setCount(count + 1)
setCount(count + 1)
// ✅ Functional updater: prev là giá trị mới nhất trong update queue
setCount(prev => prev + 1)
setCount(prev => prev + 1)
setCount(prev => prev + 1)
}Khi nào BẮT BUỘC functional form:
- Nhiều setState liên tiếp dựa trên giá trị trước đó.
- Setter gọi trong async callback (setTimeout, Promise) — closure đã stale.
- Trong useEffect cleanup hoặc với deps cũ.
Khi nào dùng direct form OK: setState 1 lần với giá trị từ event (setName(e.target.value)), không phụ thuộc state trước.