reactjs - React useCallback không được cập nhật khi trạng thái thay đổi
Ví dụ dưới đây là một đoạn trích đơn giản, nơi một component con phát ra các sự kiện dựa trên hành vi của chuột. React sau đó sẽ cập nhật DOM theo các sự kiện đã phát ra.
function SimpleSample() {
const [addons, setAddons] = React.useState<any>({
google: new GoogleMapsTile('google'),
})
const [tooltip, setTooltip] = React.useState<null | { text: string[]; x; y }>(null)
React.useEffect(() => {
// ...
}, [])
const mapEventHandle = React.useCallback(
(event: MapEvents) => {
console.log('event', event.type, tooltip) // LOG 1
if (event.type === MapEventType.mouseoverPopup_show) {
setTooltip({ text: event.text, x: event.coordinates[0], y: event.coordinates[1] })
} else if (event.type === MapEventType.mouseoverPopup_move) {
if (tooltip) setTooltip({ ...tooltip, x: event.coordinates[0], y: event.coordinates[1] })
} else if (event.type === MapEventType.mouseoverPopup_hide) {
setTooltip(null)
}
},
[tooltip]
)
console.log('render', tooltip) // LOG 2
return <MapComponent addons={addons} onEvent={mapEventHandle} />
}
Trình tự sự kiện sau đây được mong đợi:
- Khi
mouseoverPopup_showđược phát ra, rồitooltipchuyển từ null thành một giá trị, một lần render lại xảy ra - Khi
mouseoverPopup_moveđược phát, thìtooltipđược cập nhật, kích hoạt việc render lại
Điều thực sự đang xảy ra là:
- Điểm ghi log
LOG 2ghi lại giá trị cập nhật củatooltip(đúng) - Khi
mapEventHandleđược gọi lại, giá trị củatooltipbên trong closure đó (điểm logLOG 1) sẽ không bao giờ được cập nhật, luôn lànull.
Mình có đang bỏ sót điều gì không? Đang dùng hook sai sao?
Đây là một codesandbox cho nó
https://codesandbox.io/s/blissful-torvalds-wm27f
EDIT: Trên mẫu hộp mã và setTooltip thậm chí không kích hoạt kết xuất lại
Câu trả lời #1
Cảm ơn mọi người đã giúp đỡ, vấn đề có vẻ nằm trong một dependency của <MapComponent/>. Nó đã lưu trữ một tham chiếu đến callback cũ khi khởi tạo. Vẫn là một điều cần lưu ý, và có lẽ tôi sẽ không gặp phải với các component dạng class...
//something like this
class MapComponent {
emitter = this.props.onChange //BAD
emitter = (...i) => this.props.onChange(...i) //mmkay
}
Câu trả lời #2
Tôi nghĩ event.coordinates không xác định nên event.coordinates[0] gây ra lỗi.
Nếu bạn làm: setTooltip({working:'fine'}); bạn sẽ gặp lỗi kiểu nhưng nó vẫn thiết lập trạng thái toolTip và render lại.
