Skip to content

Fix #1477: Prevent scroll jump to top when resizing columns with row virtualization enabled - #1512

Open
daihua2 wants to merge 10 commits into
KevinVandy:v3from
daihua2:fix/1477-virtualization-scroll-resize
Open

Fix #1477: Prevent scroll jump to top when resizing columns with row virtualization enabled#1512
daihua2 wants to merge 10 commits into
KevinVandy:v3from
daihua2:fix/1477-virtualization-scroll-resize

Conversation

@daihua2

@daihua2 daihua2 commented Mar 27, 2026

Copy link
Copy Markdown

This fixes #1477 where scrolling jumps to the top after column resize when row virtualization is enabled.

Root cause: during resize, the body switched between memoized and non-memoized components, causing a remount and resetting virtualization scroll context.

Fix: when row virtualization is enabled, avoid that resize-time body component switch so the body instance stays stable and scroll position is preserved.

Scope: only affects the resize + row virtualization path. No API changes.

@vercel

vercel Bot commented Mar 27, 2026

Copy link
Copy Markdown

@KevinVandy is attempting to deploy a commit to the Kevin Vandy OSS Team on Vercel.

A member of the Team first needs to authorize it.

@daihua2 daihua2 changed the title fix #1477 virtualization-scroll-resize Fix #1477: Prevent scroll jump to top when resizing columns with row virtualization enabled Mar 27, 2026
KevinVandy and others added 9 commits March 27, 2026 16:06
`if (node)` 守卫把 @tanstack/virtual 唯一的清扫入口挡死了。

virtual-core 的 measureElement 只在**收到 null** 时才会遍历 elementsCache、
把已断开的元素 unobserve 并从缓存里删掉:

    measureElement = (node) => {
      if (!node) {
        this.elementsCache.forEach((cached, key) => {
          if (!cached.isConnected) { this.observer.unobserve(cached); this.elementsCache.delete(key); }
        });
        return;
      }
      ...

React 卸载时本来就会用 null 调用回调 ref —— 这三处的 `if (node)` 恰好把这一拍吞掉,
于是 ResizeObserver 一直强引用着已卸载的 <tr>/<th>,整棵子树无法回收。
类型签名 `measureElement: (node: TItemElement | null) => void` 本就接受 null,
说明这是设计好的清扫时机,不是意外。

实测(Chrome CDP,每次采样前强制 GC 只看存活):
  ~500 行的表完整滚一遍  → elementsCache 280 项其中已断开 262;残留 14900 个游离节点、
                          371 个监听器;反复滚动不再增长(每 key 最多留一份)但永不释放。
                          手工补一次 measureElement(null) → 缓存 280→18,节点当场释放。
  修复后同页 A/B(59 行) → 连滚三轮,缓存稳定在可视行数、已断开恒为 0,
                          Nodes 5668→5660、监听器 639 恒定;修复前同一页是
                          缓存 59/已断开 41、Nodes +2030 且怎么滚都不清。

三处同一形态:
  · MRT_TableBodyRow      行虚拟化(纵向滚动)
  · MRT_TableHeadCell     列虚拟化(横向滚动,泄漏表头单元格)
  · MRT_TableDetailPanel  详情面板行

表头那处另把 tableHeadCellRefs 里的条目在卸载时 delete 掉,而不是留一个悬空元素 ——
那张表是按 column.id 长期持有的。
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.

Scroll issue when resizing the column

2 participants