DEV Community

Cover image for Virtualize API call for loading Large Data in React-Select with React-Window
Dip Chowdhury
Dip Chowdhury

Posted on

Virtualize API call for loading Large Data in React-Select with React-Window

Hello internet folks! I’m pretty new to writing and sharing stuff on the internet, but I believe that by sharing our knowledge, we can build new cybernetic pyramids full of computational power! 🧑🏾‍💻🧑🏾‍💻🧑🏾‍💻

A few days ago, I was loading some data for my current clients at “CDP” where I was trying to show 1000+ data. Everything was going well until we received a requirement to scrape and find 75000+ entries and display them using React-Select, which was previously handling the 1000+ data.

Given my experience in this field, as soon as I heard the news, I knew that React wouldn’t be ideal for creating 75000+ list components to select from, especially when each of them might have their own CSS and listeners.

So what can we do? In the React-select Advance section, you might find a solution where you listen to keystrokes or the end of scrolling to bring in new data. However, I was thinking of pulling all the data back into my client and then processing it virtually using some other technique.

I came across some ideas on Stack Overflow that might help you. In another post, I may explain it in more detail, but for now, you can have a look at this code. It will help you with your problem.

Happy coding, and see you in the next post! 🕸🕸🕸

`import React, { useState, useCallback, useEffect, useRef } from "react";
import { FixedSizeList as List } from "react-window";
import InfiniteLoader from "react-window-infinite-loader";

const LOADING = 1;
const LOADED = 2;

const CustomMenuList = ({ children, initialOffset }) => {
    const itemHeight = 50;
    const [itemStatusMap, setItemStatusMap] = useState({});

    const itemStatusMapRef = useRef(itemStatusMap);
    useEffect(() => {
        itemStatusMapRef.current = itemStatusMap;
    }, [itemStatusMap]);

    const isItemLoaded = useCallback((index) => !!itemStatusMapRef.current[index], []);

    const loadMoreItems = useCallback((startIndex, stopIndex) => {
        setItemStatusMap((prevStatusMap) => {
            const newStatusMap = { ...prevStatusMap };
            for (let index = startIndex; index <= stopIndex; index++) {
                newStatusMap[index] = LOADING;
            }
            return newStatusMap;
        });

        return new Promise((resolve) => {
            setTimeout(() => {
                setItemStatusMap((prevStatusMap) => {
                    const newStatusMap = { ...prevStatusMap };
                    for (let index = startIndex; index <= stopIndex; index++) {
                        newStatusMap[index] = LOADED;
                    }
                    return newStatusMap;
                });
                resolve();
            }, 2500);
        });
    }, []);

    const Row = React.memo(({ index, style }) => {
        let label;
        if (itemStatusMap[index] === LOADED) {
            label = children[index];
        }
        return (
            <div style={{ ...style }}>
                {label || "Loading..."}
            </div>
        );
    });

    return (
        <InfiniteLoader
            isItemLoaded={isItemLoaded}
            itemCount={children.length}
            loadMoreItems={loadMoreItems}
            threshold={5}
        >
            {({ onItemsRendered, ref }) => (
                <List
                    height={500}
                    itemCount={children.length}
                    itemSize={itemHeight}
                    initialScrollOffset={initialOffset}
                    onItemsRendered={onItemsRendered}
                    ref={ref}
                    width="100%"
                >
                    {Row}
                </List>
            )}
        </InfiniteLoader>
    );
};

export default CustomMenuList;`
Enter fullscreen mode Exit fullscreen mode

Top comments (0)