DEV Community

Build your own virtual scroll - Part II

adam klein on August 09, 2019

In Part 1 we learned the basic principals behind building a virtual scroll mechanism, the math behind it, and saw some psuedo-code and some real co...
Collapse
 
slidenerd profile image
slidenerd

how would you handle window resize in this? all the heights become stale as the window is resized, only a few items are on the DOM and only their modified heights can be obtained, you have to shift everything up or down

Collapse
 
adamklein profile image
adam klein

I guess if the container's dimensions change (for any reason) we need to recalculate from scratch.
But 'scrollTop' should remain the same, so probably no need to shift anything, just display more or less nodes depending on the new height.

Collapse
 
slidenerd profile image
slidenerd

i am talking about width change on resize, the displacement of each row from the top would totally get disturbed if the width were to change on resize, how do you think that should be handled? :) thank you for the response

Thread Thread
 
adamklein profile image
adam klein

Why should the width affect the calculations? I'm not following

Thread Thread
 
slidenerd profile image
slidenerd

you record heights of 50 rows, you change the width to compress the rows, depending on contents, some of the rows increase in their height, your stored heights are now invalid

Thread Thread
 
adamklein profile image
adam klein

I think this kind of situation is problematic for a virtual scroll of this sort, since the heights are returned per row, and usually not calculated based on measuring DOM nodes' dimensions.
So I would limit the "shrink factor" of the tree view and prevent the rows from wrapping and increasing in height.

Collapse
 
devin6391 profile image
Vineet Dev

Hi Adam, I got to ask some more about performance optimisations. I have also tried to build virtual scroll with feature of two-way infinite scroll. But I got to admit that the solution I built wasn't much performant. Now, related to my project, I got two major questions:

  1. What about dynamically adding data to this component?
  2. What about mobile web performance? Mobile scroll is a totally different game which is much more complex to manage than desktop scroll and 60fps really matters there.(specially iOS)
Collapse
 
adamklein profile image
adam klein

Hi,

  1. Changing the data means you have to recalculate the positions of all the nodes
  2. In my projects, I haven't encountered any specific problems related to mobile, but obviously it depends on the device and the code

Can you share a link to your code and I'll see if I can take a look?

Collapse
 
devin6391 profile image
Vineet Dev

I cannot share as I have done this in my current organisation

Collapse
 
indumathi1701 profile image
indumathi1701

Hai, I need to perform virtual scroll in JavaScript can you provide me the code for it

Collapse
 
trumbitta profile image
William Ghelfi • Edited

Hey, thanks for this post. It's been extremely helpful in the last couple days.

I noticed you specify X items, but can scroll down only to X-1.

E.g. itemCount: 100, displayed items: 0-98

I'm trying to fix it right now, but would appreciate your help :D

Collapse
 
adamklein profile image
adam klein

Thanks!
The calculation for the end node was wrong, because it relied on the start node AFTER I reduced the renderAhead.
Also, visible count should be endNode - startNode + 1 (because if we're displaying nodes 1 to 10, we need 10 nodes, not 9).

Fixed in the example

Collapse
 
trumbitta profile image
William Ghelfi • Edited

I fixed like this:

// endNode = Math.min(itemCount - 1, endNode + renderAhead);
endNode = Math.min(itemCount, endNode + renderAhead);

But I'm not sure any side-effect would show up or not in a real world scenario.
Thoughts?

Collapse
 
derpdead profile image
Maciej Kaczorowski

Hello, Thank you for your detailed series! I've translated your code to Vue for anybody struggling with React.

gist.github.com/derpdead/f35a2ec17...

Could you give as a hint about best practise of making row measurer for auto height content?

Collapse
 
adamklein profile image
adam klein

Thanks!
I've never done that, but sounds like a nice challenge :)

Collapse
 
slidenerd profile image
slidenerd

Curious question based on your react example, why have you written const totalHeight =
childPositions[itemCount - 1] + getChildHeight(itemCount - 1) + 35; what is this 35? average row height of an item since it starts at 30 and goes till 39?

Collapse
 
adamklein profile image
adam klein

Oh, thanks for noticing!
Probably leftover - I removed it

Collapse
 
okvv profile image
Vladimir Okun • Edited

Thank you so much!!!
react-window and other solutions do not support native html tables (returns DIVs not TRs) so I had to try and solved it with no lib.

added minor cases support to your example like:

  • table header
  • TRs not shown because of additional height (let's say header height)
  • no rows at all just change the itemCount={...} prop value per needed case (0/2/10000).

forked your code with the aforementioned cases: bit.ly/38nATie
native virtual table implementation using your code in: bit.ly/36dc4nu

Collapse
 
adamklein profile image
adam klein

Cool! Thanks for the addition.
I wonder if you could make it work with position: sticky

Collapse
 
slidenerd profile image
slidenerd

Could anyone kindly add a Vue.js version of this?

Collapse
 
adamklein profile image
adam klein

Great idea! If anyone adds one I'll add to the post

Collapse
 
mirkado profile image
Iskander • Edited

Hello. I made an infinite grid with dynamic width about 2 years ago, similar to how you created a list in your exemple. However, I couldn't solve one problem: fast scrolling. If you have 100k-600kk elements and render them all, fast scrolling from top to bottom causes layout shifts and FPS drops. I rendered shop card components as grid, which include pictures, some text, and icons. I tried using debounce and render delays, but it wasn't easy, because it's depend on scroll speed. Can you give me some advice?

Collapse
 
anbu25 profile image
Anbu Venkat • Edited

@adamklein The git repo mentioned in the article for the tree implementation doesn't seem to be available. Do you have a different link to access it?
I am currently working on a similar requirement in lightning web component (salesforce), so was hoping to find any documentation/ directions related to it.

Thanks!!

Collapse
 
ceomurky profile image
Moonjongmin

Hello Adam, i really enjoy read this tutorial

How to you think of two direction virtual scroll? (horizontal and vertical)

Collapse
 
adamklein profile image
adam klein

I think that could be a great Part III :)

Collapse
 
siba2893 profile image
Daniel Sibaja

You know what would be awesome for part 3? How to make it circular. Like scrolling to the very bottom would make start from the beginning but on a infinite scroll like fashion.

Collapse
 
rmfine profile image
Michael Fine

Hi Adam, how would you handle lazy load items on scroll, and jump to a specific index/row?

Collapse
 
9z2f4f3 profile image
9z2f4F3

Hello Adam, first of all, amazing work here you've done. I want the lib to use window scroll as in the window scrollbar should be used to scroll. How would I do that? Thanks.