From 3e3d8c684fd63af7c74013f3e8fb59747f717f79 Mon Sep 17 00:00:00 2001 From: kseniyakuzina Date: Wed, 1 Jul 2026 15:20:14 +0300 Subject: [PATCH] feat(useColumnsAutoSize): add possibility to not recalc column widths on data change --- src/hooks/useColumnsAutoSize/README.md | 36 +++++++++++++------ src/hooks/useColumnsAutoSize/types.ts | 1 + .../useColumnsAutoSize/useColumnsAutoSize.tsx | 7 ++++ 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/hooks/useColumnsAutoSize/README.md b/src/hooks/useColumnsAutoSize/README.md index 27ea956..dbf41c3 100644 --- a/src/hooks/useColumnsAutoSize/README.md +++ b/src/hooks/useColumnsAutoSize/README.md @@ -98,16 +98,17 @@ const table = useTable({ #### Options -| Name | Type | Default | Description | -| ----------------------- | --------- | ------- | --------------------------------------------------------------------------------------------- | -| `minWidth` | `number` | `50` | Minimum width in pixels for any column | -| `maxWidth` | `number` | `500` | Maximum width in pixels for any column | -| `padding` | `number` | `16` | Padding in pixels to add to content width for cells | -| `headerPadding` | `number` | `24` | Padding in pixels to add to content width for headers | -| `sampleSize` | `number` | `100` | Number of rows to sample for width calculation (helps with performance) | -| `measureHeaderText` | `boolean` | `true` | Whether to include header text in width calculation | -| `respectExistingWidths` | `boolean` | `true` | Whether to preserve columns with predefined widths (size, width, or matching minSize/maxSize) | -| `respectResizedWidths` | `boolean` | `true` | Whether to preserve column widths that were resized by the user | +| Name | Type | Default | Description | +| ----------------------- | --------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `minWidth` | `number` | `50` | Minimum width in pixels for any column | +| `maxWidth` | `number` | `500` | Maximum width in pixels for any column | +| `padding` | `number` | `16` | Padding in pixels to add to content width for cells | +| `headerPadding` | `number` | `24` | Padding in pixels to add to content width for headers | +| `sampleSize` | `number` | `100` | Number of rows to sample for width calculation (helps with performance) | +| `measureHeaderText` | `boolean` | `true` | Whether to include header text in width calculation | +| `respectExistingWidths` | `boolean` | `true` | Whether to preserve columns with predefined widths (size, width, or matching minSize/maxSize) | +| `respectResizedWidths` | `boolean` | `true` | Whether to preserve column widths that were resized by the user | +| `measureOnce` | `boolean` | `false` | If `true`, widths are calculated only once (on first data render) and are NOT recalculated when data changes (e.g. sorting/filtering). Prevents columns from jumping on sort | #### Returns @@ -137,7 +138,7 @@ const {columnWidths, isMeasuring, columnsWithAutoSizes, setTableInstance} = useA 2. **Sampling**: To optimize performance, it only samples a subset of rows (configurable via `sampleSize`). 3. **Optimization**: Different measuring techniques are used for text vs React components. 4. **Respect for User Actions**: Preserves user-resized column widths and pre-defined column widths. -5. **Reactivity**: Automatically updates when table data or columns change. +5. **Reactivity**: Automatically updates when table data or columns change (unless `measureOnce` is enabled). ## Troubleshooting @@ -182,6 +183,19 @@ experimentalUseColumnsAutoSize({ }); ``` +### Columns jump / resize when sorting or changing data + +By default the hook recalculates widths whenever the data changes (including sorting, since the sampled rows change). To measure widths only once and keep them stable afterwards, enable `measureOnce`: + +```tsx +experimentalUseColumnsAutoSize({ + columns, + options: { + measureOnce: true, // calculate once, never recalc on data/sort changes + }, +}); +``` + ### Some providers needed inside the cells (for example the redux provider) If you want certain columns to keep their specified widths, set `respectExistingWidths` to true: diff --git a/src/hooks/useColumnsAutoSize/types.ts b/src/hooks/useColumnsAutoSize/types.ts index 8384550..06bc285 100644 --- a/src/hooks/useColumnsAutoSize/types.ts +++ b/src/hooks/useColumnsAutoSize/types.ts @@ -13,6 +13,7 @@ export type UseColumnsAutoSizeOptions = { measureHeaderText?: boolean; respectExistingWidths?: boolean; respectResizedWidths?: boolean; + measureOnce?: boolean; }; export type CalculateColumnWidthsArgs = UseColumnsAutoSizeOptions & { diff --git a/src/hooks/useColumnsAutoSize/useColumnsAutoSize.tsx b/src/hooks/useColumnsAutoSize/useColumnsAutoSize.tsx index 9d3b9e7..96af37d 100644 --- a/src/hooks/useColumnsAutoSize/useColumnsAutoSize.tsx +++ b/src/hooks/useColumnsAutoSize/useColumnsAutoSize.tsx @@ -31,6 +31,8 @@ export function useColumnsAutoSize({ typeof useTable > | null>(null); + const hasMeasuredRef = React.useRef(false); + const rows = tableInstance?.getRowModel().rows ?? emptyRows; const sampledRows = rows.slice(0, options?.sampleSize ?? 100); @@ -135,6 +137,7 @@ export function useColumnsAutoSize({ setColumnWidths(newWidths); setIsMeasuring(false); + hasMeasuredRef.current = true; }, 100, ), @@ -146,6 +149,10 @@ export function useColumnsAutoSize({ return; } + if (options?.measureOnce && hasMeasuredRef.current) { + return; + } + calculateWidths.cancel(); calculateWidths({ columnSizing,