From 551d2daddfa54a2aa334a1f6f90e07b9698113ee Mon Sep 17 00:00:00 2001 From: Franco Colacilli Date: Thu, 26 Jan 2023 15:34:13 -0300 Subject: [PATCH] Fix glitching behavior on scrolling up --- src/render-if-visible.tsx | 57 ++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/src/render-if-visible.tsx b/src/render-if-visible.tsx index f2b3544..08e4354 100644 --- a/src/render-if-visible.tsx +++ b/src/render-if-visible.tsx @@ -37,8 +37,38 @@ const RenderIfVisible = ({ }: Props) => { const [isVisible, setIsVisible] = useState(initialVisible) const wasVisible = useRef(initialVisible) - const placeholderHeight = useRef(defaultHeight) const intersectionRef = useRef(null) + const innerRef = useRef(null) + + const [rootHeight, setRootHeight] = useState(defaultHeight) + + useEffect(() => { + if (innerRef.current) { + const localRef = innerRef.current + const resizeObserver = new ResizeObserver((entries) => { + const resizeEntry = entries[0] + + /* Sets the height of the container if the previous value is the default one or if the current value is greater than its previous value */ + setRootHeight((prev) => { + if ( + (prev === defaultHeight && resizeEntry?.contentRect.height !== 0) || + resizeEntry?.contentRect.height > prev + ) { + return resizeEntry?.contentRect.height + } + return prev + }) + }) + + resizeObserver.observe(localRef) + return () => { + if (localRef) { + resizeObserver.unobserve(localRef) + } + } + } + return () => {} + }, [innerRef, setRootHeight, defaultHeight]) // Set visibility with intersection observer useEffect(() => { @@ -46,10 +76,6 @@ const RenderIfVisible = ({ const localRef = intersectionRef.current const observer = new IntersectionObserver( (entries) => { - // Before switching off `isVisible`, set the height of the placeholder - if (!entries[0].isIntersecting) { - placeholderHeight.current = localRef!.offsetHeight - } if (typeof window !== undefined && window.requestIdleCallback) { window.requestIdleCallback( () => setIsVisible(entries[0].isIntersecting), @@ -80,7 +106,8 @@ const RenderIfVisible = ({ } }, [isVisible]) - const placeholderStyle = { height: placeholderHeight.current } + const rootStyle = useMemo(() => ({ height: `${rootHeight}px` }), [rootHeight]) + const rootClasses = useMemo( () => `renderIfVisible ${rootElementClass}`, [rootElementClass] @@ -91,16 +118,20 @@ const RenderIfVisible = ({ ) return React.createElement(rootElement, { - children: isVisible || (stayRendered && wasVisible.current) ? ( - <>{children} - ) : ( - React.createElement(placeholderElement, { - className: placeholderClasses, - style: placeholderStyle, - }) + children: ( +
+ {isVisible || (stayRendered && wasVisible.current) ? ( + <>{children} + ) : ( + React.createElement(placeholderElement, { + className: placeholderClasses, + }) + )} +
), ref: intersectionRef, className: rootClasses, + style: rootStyle, }) }