Files
EstiMaker/src/components/LazyItem.tsx
T

53 lines
1.5 KiB
TypeScript

import type { Component, JSX } from 'solid-js';
import { createSignal, onMount, onCleanup, Show } from 'solid-js';
interface LazyItemProps {
children: JSX.Element;
estimatedHeight?: number;
rootMargin?: string;
}
/**
* A component that only renders its children when it's within (or near) the viewport.
* This is a lightweight alternative to full list virtualization.
*/
const LazyItem: Component<LazyItemProps> = (props) => {
const [isVisible, setIsVisible] = createSignal(false);
let containerRef: HTMLDivElement | undefined;
onMount(() => {
const observer = new IntersectionObserver(([entry]) => {
setIsVisible(entry.isIntersecting);
}, {
rootMargin: props.rootMargin || '400px 0px', // Pre-render 400px before appearing
threshold: 0
});
if (containerRef) {
observer.observe(containerRef);
}
onCleanup(() => {
observer.disconnect();
});
});
return (
<div
ref={containerRef}
class="lazy-item-container"
style={{
"min-height": isVisible() ? "auto" : `${props.estimatedHeight || 60}px`,
"contain-intrinsic-size": `auto ${props.estimatedHeight || 60}px`,
"content-visibility": "auto" // CSS-native optimization hint
}}
>
<Show when={isVisible()}>
{props.children}
</Show>
</div>
);
};
export default LazyItem;