Add Lazy Loading for Dashboard Components with LazyWhenVisible
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Introduced LazyWhenVisible component to optimize rendering of dashboard sections based on scroll visibility, improving performance. - Updated DashboardOverviewPage to utilize LazyWhenVisible for sections containing stats, history, or tables, enhancing user experience by loading content only when visible. - Added useScrollVisibility hook to manage visibility state, ensuring efficient resource usage during scrolling.
This commit is contained in:
parent
b212331129
commit
e3a20e6b48
@ -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 = (
|
||||
<LazyWhenVisible
|
||||
scrollRootRef={scrollRef}
|
||||
minHeight={
|
||||
isHistory || isTable ? contentHeight : 120
|
||||
}
|
||||
>
|
||||
{content}
|
||||
</LazyWhenVisible>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<InfoCollapse
|
||||
title={section.title}
|
||||
|
||||
34
src/components/Dashboard/common/LazyWhenVisible.jsx
Normal file
34
src/components/Dashboard/common/LazyWhenVisible.jsx
Normal file
@ -0,0 +1,34 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import useScrollVisibility from '../hooks/useScrollVisibility'
|
||||
|
||||
const LazyWhenVisible = ({
|
||||
scrollRootRef,
|
||||
minHeight,
|
||||
enabled = true,
|
||||
children
|
||||
}) => {
|
||||
const { targetRef, isVisible } = useScrollVisibility(scrollRootRef, {
|
||||
enabled
|
||||
})
|
||||
|
||||
if (!enabled || isVisible) {
|
||||
return children
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={targetRef}
|
||||
style={minHeight != null ? { minHeight } : undefined}
|
||||
aria-hidden
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
50
src/components/Dashboard/hooks/useScrollVisibility.js
Normal file
50
src/components/Dashboard/hooks/useScrollVisibility.js
Normal file
@ -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
|
||||
Loading…
x
Reference in New Issue
Block a user