Skip to content

fix: Avoid redundant table column measurements on re-render#4609

Open
TrevorBurnham wants to merge 1 commit into
cloudscape-design:mainfrom
TrevorBurnham:perf/memoize-table-column-widths
Open

fix: Avoid redundant table column measurements on re-render#4609
TrevorBurnham wants to merge 1 commit into
cloudscape-design:mainfrom
TrevorBurnham:perf/memoize-table-column-widths

Conversation

@TrevorBurnham

Copy link
Copy Markdown
Contributor

This PR reduces unnecessary DOM measurements when a table with "sticky" features (stickyColumns or stickyHeader) re-renders.

ColumnWidthsProvider runs a useEffect that depends on its visibleColumns array. That effect calls updateColumnWidths(), which synchronizes sticky cells by reading layout from the DOM via getBoundingClientRect() (the sticky branch of getColumnStyles). In InternalTable, the arrays passed to the provider — visibleColumnDefinitions and the derived visibleColumnWidthsWithSelection / visibleColumnIdsWithSelection — are rebuilt as fresh arrays of fresh objects on every render, causing the provider's effect to re-fire. These unnecessary calculations contribute to input lag when users type in a sticky table's searchbox.

This PR memoizes those derivations in InternalTable with useMemo:

  • visibleColumnDefinitions — keyed on columnDefinitions, columnDisplay, and visibleColumns.
  • visibleColumnWidthsWithSelection / visibleColumnIdsWithSelection — keyed on hasSelection and visibleColumnDefinitions.

Benefits

Measured getBoundingClientRect calls per re-render with unchanged columns:

Configuration Before After
stickyColumns 3 0
stickyHeader 5 3

The remaining reads come from StickyHeader's own per-render synchronization, a separate mechanism this PR does not change (a candidate for a follow-up).

Non-sticky tables benefit in a smaller way from reduced array allocations.

How has this been tested?

  • Added two unit tests in src/table/__tests__/columns-width.test.tsx:
    • does not measure column widths when re-rendering with unchanged columns — re-renders with new items but identical columnDefinitions and asserts that no getBoundingClientRect calls occur. This test fails on main (measurements still happen) and passes with this change.
    • does measure column widths when the columns change — a negative control that re-renders with an added column and asserts measurement still occurs, confirming the first test isn't trivially passing.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Memoize the visible column definitions and the width/id arrays derived
from them in InternalTable. These were rebuilt as fresh arrays on every
render, so the reference passed to ColumnWidthsProvider always changed.
That re-triggered the provider's width-sync effect, which calls
getBoundingClientRect() on every render even when columns are unchanged
(e.g. typing in the filter box), contributing to interaction lag.

With the columns memoized, the effect only re-runs when the columns
actually change.

Adds tests asserting that re-rendering with unchanged columns performs
no DOM measurements, while changing columns still does.
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.50%. Comparing base (b03b69b) to head (df5a394).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4609   +/-   ##
=======================================
  Coverage   97.50%   97.50%           
=======================================
  Files         948      948           
  Lines       30275    30317   +42     
  Branches    11039    11046    +7     
=======================================
+ Hits        29520    29562   +42     
  Misses        748      748           
  Partials        7        7           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

1 participant