nsfwapp/frontend/src/components/ui/LazyMountWhenVisible.tsx
2026-03-31 19:24:19 +02:00

56 lines
1.2 KiB
TypeScript

// frontend\src\components\ui\LazyMountWhenVisible.tsx
'use client'
import { useEffect, useRef, useState, type ReactNode } from 'react'
type Props = {
children: ReactNode
placeholder?: ReactNode
rootMargin?: string
threshold?: number
className?: string
once?: boolean
}
export default function LazyMountWhenVisible({
children,
placeholder = null,
rootMargin = '300px',
threshold = 0.01,
className,
once = true,
}: Props) {
const hostRef = useRef<HTMLDivElement | null>(null)
const [visible, setVisible] = useState(false)
useEffect(() => {
const el = hostRef.current
if (!el) return
if (visible && once) return
const io = new IntersectionObserver(
(entries) => {
const entry = entries[0]
if (!entry) return
if (entry.isIntersecting) {
setVisible(true)
if (once) io.disconnect()
} else if (!once) {
setVisible(false)
}
},
{ rootMargin, threshold }
)
io.observe(el)
return () => io.disconnect()
}, [visible, once, rootMargin, threshold])
return (
<div ref={hostRef} className={className}>
{visible ? children : placeholder}
</div>
)
}