How to remove redundant elements from the beginning of an array when implementing infinite scroll in react?

There is a page that receives a data stream of a YouTube video. I output this data to the page and implement infinite scrolling with observer.
Visualization:
enter image description here

Problem. When there are more than 200-300 items in the array with data, performance problems start. And if you start deleting elements from the beginning of the array, then naturally the whole list of elements moves upwards and it is inconvenient functionally.

// types
import {VideoAtFlow} from '../../../../types';
// react- redux
import {useCallback, useEffect, useRef, useState } from 'react';
import {useGetFeedMutation} from '../../../../app/services/queries/videoflow';
import {selectVideoflow} from '../../../../features/video-flow/videoflowSlice';
import {useAppSelector} from '../../../../hooks/hooks';
// components
import {DisplayContent} from './display-content/DisplayContent';
import {IfSpin} from '../../../../widgets';
// scss
import mod from './style.module.scss';

export const VideoFlowContentComponents = () => {
    const [video, setVideo] = useState<VideoAtFlow[]>([]);
    const [fetching, setFetching] = useState(false);
    const [count, setCount] = useState(0);
    const loaderRef = useRef(null);

    const [getVideo] = useGetFeedMutation()

    const param = {
        from: count,
        date_published_at: "now-1w",
        sort: "views_per_hour",
        category: "any",
        country: "RU",
        min_iq_score: 0,
        max_iq_score: 100,
        content_type: "any"
    }

    const fetchData = useCallback(async () => {
        if (fetching) return;
        requestData()
    }, [count, fetching]);
    
    useEffect(() => {
        const observer = new IntersectionObserver((entries) => {
          const target = entries[0];
          if (target.isIntersecting) {
            fetchData();
            setCount(count + 20)
          }
        });
    
        if (loaderRef.current) {
          observer.observe(loaderRef.current);
        }
    
        return () => {
          if (loaderRef.current) {
            observer.unobserve(loaderRef.current);
          }
        };
    }, [fetchData]);

    const requestData = async () => {
        setFetching(true);
        const response = await getVideo(param);
        const data="data" in response ? response.data : [];
        setVideo((newArray: any) => {
            let array = [...(newArray || []), data]
            let combinedArray = [].concat(...array)
            return combinedArray
        });
        setFetching(false);
    }

    const {flowOrPlaylists} = useAppSelector(selectVideoflow);
    const data = flowOrPlaylists ? [] : video 
    
    return (
        <div className={mod.wrapper}>
            <DisplayContent
                data={data}
            />
            <div
                className={mod.triggerbox}
                ref={loaderRef}>{fetching && <IfSpin height="10%"/>}
            </div>
        </div>
    );
};

We need to somehow optimize the process that when the array with data became more than 100 elements, 20 elements were removed from the beginning of the array with each new query. In this case, the “tile” with elements in the browser should not change, jump, shift, etc. in any way.

  • Are you following all recommended practices when it comes to performance? Are you components pure, memoized and have stable key?

    – 

Leave a Comment