Simple Infinite Scrollable List— MUI Compatible

Jeremy Tong
2 min readOct 4, 2023

I was recently looking for solutions to provide an infinite scrollable list component in React. While react-window is often used and optimizes customizability and performance, I found it a bit over-engineered for my usage.

Unlike most implementations that are coupled with lazy-loading or fetch-on-scroll behavior, I wanted a simple list that would increase in size as you scroll to the bottom of its list items, i.e. to limit page size on render. In other words, the full data is already available, but you still want to buffer the injection of list items into the DOM.

import { useEffect, useRef, useState } from 'react'

export default function InfiniteNonqueryList({
items,
defaultNumItems = 5,
increment = 5,
resetDisplayDependencies,
offsetIncrement = 30,
}: {
items: React.ReactNode[] // list item components
defaultNumItems?: number // number of items to render at start
increment?: number // number of additional items to render when you scroll to the bottom
resetDisplayDependencies: any[] // dependencies that would trigger the list resetting its items
offsetIncrement?: number // number of pixels above the bottom list element where you'd want to buffer the increment
}) {
const [numItemsToDisplay, setNumItemsToDisplay] = useState(defaultNumItems)
useEffect(() => {
setNumItemsToDisplay(defaultNumItems)
}, [defaultNumItems, ...resetDisplayDependencies])

const myRef = useRef<HTMLDivElement | null>(null)
useEffect(() => {
const handleScroll = () => {
if (
(myRef.current?.offsetTop || Number.POSITIVE_INFINITY) <=
window.innerHeight +
document.documentElement.scrollTop +
offsetIncrement
) {
setNumItemsToDisplay((curr) => curr + increment)
}
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [increment, offsetIncrement])

return (
<>
<div>{items.slice(0, numItemsToDisplay)}</div>
<div ref={myRef} />
</>
)
}

The above implementation is a simple component that solves addresses this functionality. It accepts an array of React.ReactNode list items and renders a subset of them depending on the scroll’s cursor. The props adjust the specific behavior of the rendering.

How it works… The scroll is captured by the bottom myRef that is an empty box element that indicates the bottom of the list in y-coordinates (i.e. offsetTop). When the cursor goes below the element, the next increment of items will render.

Though this component does not support fetching, you can extend functionality from the setNumItemsToDisplay() callback to include a data fetch. While this implementation is not nearly as efficient as a fully virtualized list as in react-window, it’s biggest advantage is not requiring pre-specified sizing of list items or the list itself (i.e. height in pixels).

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Jeremy Tong
Jeremy Tong

Written by Jeremy Tong

Startup-Focused Software Developer

No responses yet

Write a response