If you need to show many list items, one common technique to overcome this issue, is to apply the concept of “virtual scrolling”.

You only render visible items on the page, and a few more to pre-load them.

This makes the experience “infinite” and smooth.

React library

Looking through GitHub and NPM I found react-tiny-virtual-list.

Install the library with

npm install react-tiny-virtual-list

Then I used it this way:

import VirtualList from 'react-tiny-virtual-list';

const Timeline = (props) => {
render (props) {
const timeline = (props.timeline || [])
.filter(t => retweets ? true : !t.retweet)
.filter(t => replies ? true : !t.reply)

...

return (
<VirtualList
width='100%'
height='100vh'
itemCount={timeline.length}
itemSize={(i => {
const item = timeline[i]
const text = item.formatted || item.text || '\n'
const newLinesCount = text.split('\n').length
return 200 + newLinesCount * 15 + text.length * 0.3
})}
overscanCount={10}
renderItem={({ index, style, t = timeline[index] }) =>
<div id={`t${+new Date(t.date)}`} tabIndex={index + 2} key={index} style={style} class={timelineStyles.tweet + ' p-0 border-0 py-5'}>
<div class=''>
<small class=''><a href={t.link} tabIndex={-1} target='_blank' rel='noopener noreferrer'>{new Date(t.date).toISOString().substring(11, 16)}</a></small>
<h5 class=''>
<div style={`background-size: contain; background-image: url(${t.authorAvatar})`} />
{t.author}
</h5>
<span class=''><p>{t.date}</p></span>
</div>
<p class=''><Linkify>{t.formatted || t.text}</Linkify></p>
</div>}
/>
)
}
}

This achieves the following:

  • a list of items (with 10 overscan)
  • dynamic itemSize based on text and content length

I think this is beautifully simple, especially performant!

Seamless integration with Preact

Yes!

If you’re using the preact-cli, or configured your bundler accordingly, you have support for preact/compat built in.

Which makes this a performance improvement without heavy shimming or other fluff.