Mid #hooks#closure#useEffect
Stale closure trong React hooks là gì và xử lý ra sao?
⚡ Trả lời nhanh
Mỗi lần render tạo ra closure riêng, nắm giá trị state/props của lần render đó. Callback dài hạn (setInterval, listener) với deps rỗng sẽ đọc giá trị cũ. Sửa bằng updater function, khai báo đủ deps, hoặc giữ giá trị mới nhất trong ref.
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
console.log(count); // luôn in 0: closure của lần render đầu
setCount(count + 1); // luôn set thành 1
}, 1000);
return () => clearInterval(id);
}, []); // thiếu count
}
Cách sửa, theo thứ tự ưu tiên:
- Updater:
setCount(c => c + 1)rồi không cầncounttrong deps. - Khai báo đầy đủ deps (
[count]), chấp nhận effect chạy lại. Bậtreact-hooks/exhaustive-deps. - Cần callback ổn định nhưng đọc giá trị mới nhất: lưu vào ref.
const latest = useRef(count);
useEffect(() => { latest.current = count; });
useEffect(() => {
const id = setInterval(() => console.log(latest.current), 1000);
return () => clearInterval(id);
}, []);