Đây là dấu hiệu effect đang trộn hai loại logic: phần reactive (kết nối lại khi roomId đổi) và phần không reactive (gọi callback mới nhất khi có tin nhắn). Cha tạo onMessage mới mỗi render nên deps đổi liên tục.
Các hướng xử lý theo thứ tự ưu tiên:
1. Ổn định function ở phía cha bằng useCallback với deps chính xác. Cách này chỉ đủ khi bản thân callback thật sự ít đổi.
2. Tách phần không reactive ra khỏi effect. React có useEffectEvent (đang thử nghiệm) cho đúng việc này — hàm luôn "thấy" props/state mới nhất nhưng không phải là dependency:
const onReceive = useEffectEvent((msg) => {
onMessage(msg, theme) // always the latest values
})
useEffect(() => {
const conn = createConnection(roomId)
conn.on('message', onReceive)
conn.connect()
return () => conn.disconnect()
}, [roomId]) // only roomId is reactive3. Tự làm bằng ref nếu chưa muốn dùng API thử nghiệm: const cbRef = useRef(onMessage), cập nhật trong một effect riêng, và trong handler gọi cbRef.current(msg).
Không nên: giữ deps rỗng rồi tắt lint — callback sẽ đóng băng ở lần render đầu và đọc state cũ.