Skip to content

Virtualized list wrapper keeps stale height after data changes #1077

Closed as duplicate

Description

@kosovatoolsadmin

Describe the bug

Summary

List uses useWindowVirtualizer for row virtualization, but the outer div’s inline
height is read directly from rowVirtualizer.getTotalSize() during render. Because the
virtualizer instance is stable and the getter mutates internal state without changing referential
identity, React never receives a new height value when the rows array is filtered or otherwise
resized. The wrapper therefore preserves an outdated, overly tall height, leaving a large blank
spacer below the visible rows and causing scroll position jumps.

Impact

Any operation that changes the number of rows (search, filters, pagination reset) leaves the
list container at its previous height. Users see excessive empty space and the scroll bar no
longer reflects the actual result size.

Root Cause

getTotalSize() is invoked inline inside JSX. The virtualizer recomputes its measurement cache,
but React doesn’t detect that the returned string (e.g., "32000px") should change because the
component never re-renders with a different computed value tied to the rows count.

Fix in my case

Memoize the total height using useMemo(() => rowVirtualizer.getTotalSize(), [rowVirtualizer, rows.length]) and pass that memoized number to the style prop. This forces a fresh height
string whenever the virtualizer’s count changes, keeping the spacer in sync. Implemented in commit

Your minimal, reproducible example

kosovatools/kosovatools.org@da4a201

Steps to reproduce

.

Expected behavior

Height react to count change

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

Firefox

tanstack-virtual version

3.13.12

TypeScript version

5.7.3

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.

Activity

  1. changed the title [-]Virtualized victim list wrapper keeps stale height after data changes[/-] [+]Virtualized list wrapper keeps stale height after data changes[/+] on Nov 8, 2025
  2. shunn2 commented on Dec 16, 2025

    @shunn2
    Contributor

    Hi @kosovatoolsadmin Maybe #1085 I think this PR will solve the issue you raised

  3. KillerCodeMonkey commented on Apr 13, 2026

    @KillerCodeMonkey

    no need for that, just check if you have memorized your getItemKey function.
    Maybe there are some deps missing when the key should be recalculated.

      const getItemKey = useCallback(
        (index) => index,
        // window width, height or items length changed
        [width, height, items.length]
      )
  4. piecyk commented on Oct 10, 2026

    @piecyk
    Collaborator

    Thanks for the report! It looks like your app has reactCompiler: true in apps/web/next.config.ts. The compiler memoizes rowVirtualizer.getTotalSize() against the stable rowVirtualizer instance, so the value isn't recomputed when count changes. Without the compiler, calling getTotalSize() during render always reflects the current count (covered by a virtual-core test since #1112). Note that #1085 was reverted in #1112 because it caused infinite re-renders (#1092).

    Workaround: opt the component out of the compiler by adding the "use no memo" directive at the top of VictimList (the component that calls useWindowVirtualizer):

    export function VictimList(props) {
      "use no memo";
      const rowVirtualizer = useWindowVirtualizer({ /* ... */ });
      // ...
    }

    Your explicit useMemo keyed on victims.length also works, but "use no memo" keeps the rest of the virtualizer output (getVirtualItems(), etc.) fresh too.

    Closing as a duplicate of #736; the React Compiler incompatibility is tracked in #1119. If "use no memo" doesn't fix it for you, let us know and we'll reopen.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions