Remix.run Logo
mirzap 3 days ago

Because he constructs a giant JSON by joining individual entries. Rendering that directly on the DOM will always cause the performance issues (even at the 10k entries). That's why you need to use virtualized list, it can be done in plain JS or using libraries like react-virtualized.

This works, plain JS 150k rows

    <style>
        #viewport {
            height: 600px;
            overflow-y: scroll;
            position: relative;
            border: 1px solid #ccc;
            width: 400px;
            margin: auto;
        }

        .item {
            position: absolute;
            left: 0;
            right: 0;
            height: 30px;
            padding: 5px;
            box-sizing: border-box;
            border-bottom: 1px solid #eee;
            font-family: Arial, sans-serif;
        }
    </style>

    <div id="viewport">
        <div id="content"></div>
    </div>


    <script>
        const viewport = document.getElementById('viewport');
        const content = document.getElementById('content');
        const itemHeight = 30;
        const totalItems = 150000;

        const items = Array.from({length: totalItems}, (_, i) => ({
            id: i + 1,
            name: `User #${i + 1}`
        }));

        content.style.height = `${totalItems * itemHeight}px`;

        function render() {
            const scrollTop = viewport.scrollTop;
            const viewportHeight = viewport.clientHeight;
            const start = Math.floor(scrollTop / itemHeight);
            const end = Math.min(totalItems, start + Math.ceil(viewportHeight / itemHeight) + 10);

            content.innerHTML = '';

            for (let i = start; i < end; i++) {
                const div = document.createElement('div');
                div.className = 'item';
                div.style.top = `${i * itemHeight}px`;
                div.textContent = items[i].name;
                content.appendChild(div);
            }
        }

        viewport.addEventListener('scroll', render);
        render();
    </script>