0

I am trying to render a huge list of data in React. I know I can use react-window for this usecase but wanted to try if we can implement a similar window based rendering using Intersection Observer API.

I have written this component to try the same. But Here my component is rendering the whole 10,000 divs even if it is not in view port as i am iterating over the data. Is there any way to prevent rendering if the element is not there in viewport similar to react-window. Thank you in advance.

import React from 'react';
import './CustomVirtualizedList.css';
import faker from 'faker';

const generateFakeData = (() => {
    const data = [];
    for (let i = 0; i < 10000; i++) {
        data.push({ id: i, selected: false, label: faker.address.state() })
    }
    return () => data;
})();

function getRandomColor() {
    var letters = '0123456789ABCDEF';
    var color = '#';
    for (var i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
}

const ListElement = (props) => {
    const [visible, setVisible] = React.useState(false);
    const {containerRef} = props;
    const elementRef = React.useRef();
    let intersectionObserver;

    const onVisibilityChange = ([entry]) => {
        setVisible(entry.isIntersecting)
    }

    React.useEffect(() => {
        console.log(props);
        intersectionObserver = new IntersectionObserver(onVisibilityChange, containerRef.current);
        intersectionObserver.observe(elementRef.current);
        return () => {
            intersectionObserver.disconnect()
        }
    }, [])

    return <div
        ref={elementRef}
        style={{ backgroundColor: getRandomColor() }}
        className="listElement">
        {visible ? 'I am visible' : 'I am not visible'}
    </div>
}

export const ListContainer = () => {
    const containerRef = React.useRef();
    const [data, setData] = React.useState(generateFakeData())

    return (
        <div className="listContainer">
            {data.map(val => {
                return <ListElement containerRef={containerRef} {...val} />
            })}
        </div>
    );
};
  • Your callback is not checking the individual entries. You are getting an array of entries and need to use bracket notation to check if it is intersecting. ` const onVisibilityChange = ([entries]) => { setVisible(entries[0].isIntersecting) } } ` You are also probably better off creating one instance of the observer and passing it to your list item to observe that item instead of creating a new observer for each item in your list. – Davidicus Jun 20 '22 at 16:51

0 Answers0