Skip to content

Fixed-header tables force one getBoundingClientRect per column on every mount (ResizeObserver-driven MeasureCell) #1507

Description

@amisis97

Environment

  • @rc-component/table: 1.10.4 (via antd 6.5.3)
  • @rc-component/resize-observer: 1.1.2
  • Chrome, production build, 4x CPU throttle (DevTools)

What we observed

Any table mounted with a fixed/scrollable header (scroll.y set, i.e. fixHeader true) renders a hidden "measure row" with one MeasureCell per column. Each MeasureCell wraps its cell in a ResizeObserver (Body/MeasureCell.js), and on the initial observe, onInternalResize (useResizeObserver.js:20) calls target.getBoundingClientRect() once per cell.

On a ~40-column table, we measured 86 getBoundingClientRect calls totaling ~547ms of forced-layout self-time on a single cold mount, instrumented by wrapping HTMLElement.prototype.getBoundingClientRect/offsetWidth and measuring with performance.now(). This is currently the dominant forced-layout cost on table mount in our app (a general-purpose ERP list view), well above what column count alone would suggest — the reads don't appear to be batched into a single reflow.

Question / ask

Is per-column ResizeObserver-driven measurement (as opposed to reading all column offsetWidths in one synchronous batch, which the browser can usually satisfy with a single layout pass) intentional, or is there a lower-cost path we're missing (e.g. skipping remeasurement when explicit pixel widths are already provided for every column)? Happy to share a minimal repro or profiling trace if useful.

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