TanStack / TanStack/virtual

Redundant repaints, because of ResizeObserver. It send events when when list got hiden with css display property.

Open
#823 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7.1k
Forks
466
Avg merge
2d 31m
Merged PRs (30d)
13

Description

Describe the bug

Hi, I have app that has tabbed view with multiple lists. When tab switched all elements in list disapears. After it went back to visible state, list got rerender.

Tab view implemented as such:

<div id="tab_view">
  <div id="tab_bar>...</div>
  <div id="viewport">
    <div id="tab_1" style="display:none">  <VirtualList ... /> </div>
    <div id="tab_2" style="display:block"> <VirtualList ... /> </div>
    <div id="tab_3" style="display:none">  <VirtualList ... /> </div>
  </div>
</div>

Things that happens:

  • Current active tab: #tab_1, 30 elements rendered within <VirtualList>
  • User clicks on tab associated with #tab_2
  • #tab_1 style property changed from block -> none
  • [Bad Thing Here:] <VirtualList/> within #tab_1 notified via resize observer, with event where all sizes === 0
  • All list elements inside #tab_1 got unmounted
  • #tab_2 style property changed from none -> block
  • <VirtualList/> within #tab_2 notified via resize observer with current view size
  • <VirtualList/> within #tab_2 populated with visible elements

The problem with this behaviour is that elements getting rerendered when user switch tabs. In most cases it is not a big problem, but in my case it make lot's of flickering, because list displays elements with images. And for some reason, images couldn't be displaye immediatly. Also it just useless work that browser should redo each time user show/hide lists.

Your minimal, reproducible example

https://stackblitz.com/edit/vitejs-vite-1ucf3g?file=src%2FApp.tsx

Steps to reproduce
  • Open stackblitz example
  • Click on tabs above listview
  • Check repaint counts
  • Check DOM in devtools (list contents specifically)
Expected behavior

It would be great, if handler of ResizeObserver checks if offsetParrent of observed element is not equal to null. It it is, that means that observed element is invisible, and all layouting/rerendering of list should be skipped.

Or at least, there should be some flag that allows to skip such rerenders.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

Windows 10
Chrome 128

tanstack-virtual version

solid-virtual 3.10.6

TypeScript version

5.4.5

Additional context

No response

Terms & Code of Conduct
  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked StackBlitz reproduction in src/App.tsx and reproduce the ResizeObserver events while switching tabs. Then trace the virtual list's ResizeObserver handling and determine how hidden lists should be treated without preventing visible lists from updating. Done means tab switches no longer cause unnecessary hidden-list rerenders, while the active list still displays correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.