import { useState, useEffect, useCallback, useMemo } from 'react'; import { IUsePartialRenderProps } from '../types'; export const usePartialRender = ({ ref, elementSize, direction = 'vertical', disable, }: IUsePartialRenderProps) => { const [shift, setShift] = useState(0); const [containerSize, setContainerSize] = useState(0); useEffect(() => { if (disable) return; const container = ref?.current as Element | null; if (container) { const size = direction === 'vertical' ? container.clientHeight : container.clientWidth; setContainerSize(size); } }, [ref, direction, disable]); const { ratio, visibleCount } = useMemo( () => ({ ratio: elementSize / containerSize, visibleCount: Math.floor(containerSize / elementSize), }), [elementSize, containerSize] ); const itemsCount = useMemo( () => Math.floor((containerSize / elementSize) * (1.4 + ratio)), [containerSize, elementSize, ratio] ); const buffer = useMemo( () => Math.floor((itemsCount - visibleCount) / 2) + 2, [visibleCount, itemsCount] ); const handleScroll = useCallback(() => { const container = ref?.current as Element | null; if (container) { const scrollPosition = direction === 'vertical' ? container.scrollTop : container.scrollLeft; const newShift = Math.floor(scrollPosition / elementSize); setShift((prev) => (newShift !== prev ? newShift : prev)); } }, [elementSize, direction, ref]); useEffect(() => { const container = ref?.current as Element | null; if (!disable) { container?.addEventListener('scroll', handleScroll); } return () => container?.removeEventListener('scroll', handleScroll); }, [handleScroll, ref, direction, disable]); return { from: Math.max(shift - buffer, 0), to: shift + itemsCount, }; };