1
This commit is contained in:
Generated
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
import * as React from 'react';
|
||||
import { observe, unobserve } from "./utils/observerUtil";
|
||||
import { useEvent } from '@rc-component/util';
|
||||
export default function useResizeObserver(enabled, getTarget, onDelayResize, onSyncResize) {
|
||||
// ============================= Size =============================
|
||||
const sizeRef = React.useRef({
|
||||
width: -1,
|
||||
height: -1,
|
||||
offsetWidth: -1,
|
||||
offsetHeight: -1
|
||||
});
|
||||
|
||||
// =========================== Observe ============================
|
||||
|
||||
// Handler
|
||||
const onInternalResize = useEvent(target => {
|
||||
const {
|
||||
width,
|
||||
height
|
||||
} = target.getBoundingClientRect();
|
||||
const {
|
||||
offsetWidth,
|
||||
offsetHeight
|
||||
} = target;
|
||||
|
||||
/**
|
||||
* Resize observer trigger when content size changed.
|
||||
* In most case we just care about element size,
|
||||
* let's use `boundary` instead of `contentRect` here to avoid shaking.
|
||||
*/
|
||||
const fixedWidth = Math.floor(width);
|
||||
const fixedHeight = Math.floor(height);
|
||||
if (sizeRef.current.width !== fixedWidth || sizeRef.current.height !== fixedHeight || sizeRef.current.offsetWidth !== offsetWidth || sizeRef.current.offsetHeight !== offsetHeight) {
|
||||
const size = {
|
||||
width: fixedWidth,
|
||||
height: fixedHeight,
|
||||
offsetWidth,
|
||||
offsetHeight
|
||||
};
|
||||
sizeRef.current = size;
|
||||
|
||||
// IE is strange, right?
|
||||
const mergedOffsetWidth = offsetWidth === Math.round(width) ? width : offsetWidth;
|
||||
const mergedOffsetHeight = offsetHeight === Math.round(height) ? height : offsetHeight;
|
||||
const sizeInfo = {
|
||||
...size,
|
||||
offsetWidth: mergedOffsetWidth,
|
||||
offsetHeight: mergedOffsetHeight
|
||||
};
|
||||
|
||||
// Call the callback immediately, let the caller decide whether to defer
|
||||
// onResize(sizeInfo, target);
|
||||
onSyncResize?.(sizeInfo, target);
|
||||
|
||||
// defer the callback but not defer to next frame
|
||||
Promise.resolve().then(() => {
|
||||
onDelayResize?.(sizeInfo, target);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Dynamic observe
|
||||
const isFuncTarget = typeof getTarget === 'function';
|
||||
const funcTargetIdRef = React.useRef(0);
|
||||
React.useEffect(() => {
|
||||
const target = isFuncTarget ? getTarget() : getTarget;
|
||||
if (target && enabled) {
|
||||
observe(target, onInternalResize);
|
||||
} else if (enabled && isFuncTarget) {
|
||||
funcTargetIdRef.current += 1;
|
||||
}
|
||||
return () => {
|
||||
if (target) {
|
||||
unobserve(target, onInternalResize);
|
||||
}
|
||||
};
|
||||
}, [enabled,
|
||||
// If function target resolves after a parent render, the bumped ref value
|
||||
// lets the next render re-run this effect without watching the function identity.
|
||||
isFuncTarget ? funcTargetIdRef.current : getTarget]);
|
||||
}
|
||||
Reference in New Issue
Block a user