Skip to content

Conversation

@Anders2303
Copy link
Collaborator

Updates the Virtualization component:

  • Made the onScroll give the end-index aswell
  • Fixed a re-render loop that would occur if a given onScroll handler wasn't stable
    • Basically: there was a "previousIndex" variable that was being reset everytime the effect was remade
  • Fixed the table scroll jumping back to the top (or props.startIndex everytime the data list updates)
    • The scroll position will now stick within it's range as data is added.
    • If props.startIndex changes, the component will scroll to it's value

Copy link
Collaborator

@rubenthoms rubenthoms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all a nice improvement as it removes a significant amount of code and stabilizes the component.

A couple of comments (general, not only related to your changes):

  • Usually, when having a controlled component, you would not want onChange callbacks to trigger when you provide new data (hence the programmatic check before). However, as the scroll event is actually a DOM event, I think it's okay to mirror it (as long as we document it clearly enough). I checked the issues which had required this implementation back then and it's no longer causing issues firing the event also on programmatic changes. So we are good with your change. However, we should keep an eye on it just in case. Alternatively, we could also add an optional prop for controlling the behaviour.
  • You removed the tail-overscan (rendering one more item than visible at the end). I think it is good to keep the overscan as it improves the UX by avoiding placeholder pop-ins on scroll. We could add a prop overscan/overscanCount for symmetric overscan (head & tail) that defaults to 1.
  • Two things I would change in the mountScrollEffect
    1. Assign props.containerRef.current to a local variable inside the effect and use that variable in the unmount return function. ref.current can change in between and would cause the event listener to never be removed. Also, you can do the assignment at the very beginning and add an early return when null directly after - this way we can remove the later checks.
    2. Replace props.items with props.items.length - we do not really care about the individual items, only about the size of the array.
  • We should add a guard for props.itemSize to guarantee > 0 (see division by itemSize).
  • I think we don't really need to use lodash.isEqual to compare the ranges - a more native check is sufficient - but either is fine as we're using lodash all over the place.

@Anders2303
Copy link
Collaborator Author

  • As discussed: I changed the onScroll to be onStartIndexChange, and added a onRangeComputed to be more idiomatic with the controlled-pattern
  • Added overscan prop. Made it possible to specify head and tail if wanted; this might be relevant for the table comp, as it's sticky header causes the entire list render to be offset
  • Fixed, and cleaned up the hook a little bit for readability
  • Guard addded
  • I'll just leave that as is, since we use isEqual a bunch of places. Generally I just think doing (new.start === prev.start && new.end === prev.end) is needlessly cumbersome and harder to read; whereas isEqual does the same, and makes it immediately clear what you're checking.

@Anders2303 Anders2303 requested a review from rubenthoms August 18, 2025 11:20
Copy link
Collaborator

@rubenthoms rubenthoms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good! Some additional improvements to consider.

Copy link
Collaborator

@rubenthoms rubenthoms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discovered one tiny issue with the end index calculation. The end index should be inclusive the last (halfway) visible element.

Copy link
Collaborator

@rubenthoms rubenthoms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all very good. Some nitpicks. There is also some issue with the Select component now that is probably related to the changes in Virtualization. To reproduce you can select a couple of ensembles, e.g. 8, and add a Simulation time series module. Then select an ensemble at the bottom (without scrolling) - the select content is automatically scrolling now (see video). This should definitely be addressed.

Recording.2025-09-24.093826.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants