[fix] Avoid needing to memoize onLayout callbacks

If 'onLayout' is an inline function, it could cause the DOM node to enter a
cycle of being observed/unobserved with the result that 'onLayout' was
constantly called.

Fix #1704
This commit is contained in:
Nicolas Gallagher
2020-08-17 11:10:53 -07:00
parent 7fc17d01cc
commit 77bdb9086e
+16 -7
View File
@@ -61,23 +61,32 @@ function getResizeObserver(): ?ResizeObserver {
export default function useElementLayout(
ref: ElementRef<any>,
onLayout?: (e: LayoutEvent) => void
onLayout?: ?(e: LayoutEvent) => void
) {
const observer = getResizeObserver();
useLayoutEffect(() => {
const node = ref.current;
if (node != null && observer != null && typeof onLayout === 'function') {
observer.observe(node);
// $FlowFixMe
if (node != null) {
node[DOM_LAYOUT_HANDLER_NAME] = onLayout;
}
}, [ref, onLayout]);
// Observing is done in a separate effect to avoid this effect running
// when 'onLayout' changes.
useLayoutEffect(() => {
const node = ref.current;
if (node != null && observer != null) {
if (typeof node[DOM_LAYOUT_HANDLER_NAME] === 'function') {
observer.observe(node);
} else {
observer.unobserve(node);
}
}
return () => {
if (node != null && observer != null) {
observer.unobserve(node);
// $FlowFixMe
delete node[DOM_LAYOUT_HANDLER_NAME];
}
};
}, [ref, onLayout, observer]);
}, [ref, observer]);
}