diff --git a/src/components/Dashboard/common/DashboardOverviewPage.jsx b/src/components/Dashboard/common/DashboardOverviewPage.jsx index 0549dfb4..2d1cb7dc 100644 --- a/src/components/Dashboard/common/DashboardOverviewPage.jsx +++ b/src/components/Dashboard/common/DashboardOverviewPage.jsx @@ -16,6 +16,7 @@ import ScrollBox from './ScrollBox' import InfoCollapse from './InfoCollapse' import StatsDisplay, { StatsViewButton } from './StatsDisplay' import ModelHistoryDisplay from './ModelHistoryDisplay' +import LazyWhenVisible from './LazyWhenVisible' import ObjectTable from './ObjectTable' import DashboardOverviewFlexColumns from './DashboardOverviewFlexColumns' import useCollapseState from '../hooks/useCollapseState' @@ -734,12 +735,11 @@ const DashboardOverviewPage = ({ } const renderCollapse = (section, dragHandle = null) => { - const statsObjectType = - section.content?.type === StatsDisplay - ? section.content.props?.objectType - : null + const isStats = section.content?.type === StatsDisplay + const statsObjectType = isStats ? section.content.props?.objectType : null const isHistory = section.content?.type === ModelHistoryDisplay const isTable = section.content?.type === ObjectTable + const isLazyContent = isStats || isHistory || isTable const resizable = isHistory || isTable const defaultHeight = isHistory ? DEFAULT_HISTORY_HEIGHT @@ -757,6 +757,19 @@ const DashboardOverviewPage = ({ : cloneElement(content, { scrollHeight: `${contentHeight}px` }) } + if (isLazyContent && content) { + content = ( + + {content} + + ) + } + return ( { + const { targetRef, isVisible } = useScrollVisibility(scrollRootRef, { + enabled + }) + + if (!enabled || isVisible) { + return children + } + + return ( +
+ ) +} + +LazyWhenVisible.propTypes = { + scrollRootRef: PropTypes.shape({ current: PropTypes.instanceOf(Element) }), + minHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + enabled: PropTypes.bool, + children: PropTypes.node +} + +export default LazyWhenVisible diff --git a/src/components/Dashboard/hooks/useScrollVisibility.js b/src/components/Dashboard/hooks/useScrollVisibility.js new file mode 100644 index 00000000..59c09675 --- /dev/null +++ b/src/components/Dashboard/hooks/useScrollVisibility.js @@ -0,0 +1,50 @@ +import { useEffect, useRef, useState } from 'react' + +const useScrollVisibility = ( + scrollRootRef, + { rootMargin = '200px 0px', threshold = 0, enabled = true } = {} +) => { + const targetRef = useRef(null) + const [isVisible, setIsVisible] = useState(!enabled) + + useEffect(() => { + if (!enabled || isVisible) return undefined + + const target = targetRef.current + if (!target) return undefined + + let observer + let cancelled = false + + const attach = () => { + if (cancelled) return + + const root = scrollRootRef?.current + if (!root) { + requestAnimationFrame(attach) + return + } + + observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting) { + setIsVisible(true) + } + }, + { root, rootMargin, threshold } + ) + observer.observe(target) + } + + attach() + + return () => { + cancelled = true + observer?.disconnect() + } + }, [scrollRootRef, rootMargin, threshold, enabled, isVisible]) + + return { targetRef, isVisible } +} + +export default useScrollVisibility