Skip to content

Commit

Permalink
Optimize table rendering (#1715)
Browse files Browse the repository at this point in the history
  • Loading branch information
kuzmadom authored Oct 21, 2024
1 parent 7216ad7 commit 633ac23
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';

import block from 'bem-cn-lite';
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import type {StringParams, TableCell, TableCellsRow, TableCommonCell} from 'shared';
import {BackgroundTable} from 'ui/libs/DatalensChartkit/ChartKit/plugins/Table/renderer/components/Table/BackgroundTable';

Expand Down Expand Up @@ -271,7 +272,11 @@ export const Table = React.memo<Props>((props: Props) => {
<BackgroundTable
dimensions={widgetDimensions}
data={{header, body, footer}}
onChangeMinWidth={setCellMinWidth}
onChangeMinWidth={(colWidths) => {
if (!isEqual(cellMinSizes, colWidths)) {
setCellMinWidth(colWidths);
}
}}
/>
</React.Fragment>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function getNoDataRow(colSpan = 1): BodyRowViewData {
};
}

function getFooterRows(table: Table<TData>, leftPositions: number[]) {
function getFooterRows(table: Table<TData>, leftPositions: (number | undefined)[]) {
return table.getFooterGroups().reduce<FooterRowViewData[]>((acc, f) => {
const cells = f.headers.map<FooterCellViewData>((cell) => {
const columnDef = cell.column.columnDef;
Expand Down Expand Up @@ -180,11 +180,6 @@ export const usePreparedTableData = (props: {
const headers = table.getHeaderGroups();
const tableRows = table.getRowModel().rows;

const enableRowGrouping = React.useMemo(
() => data.head?.some((cell) => get(cell, 'group', false)),
[data.head],
);

const rowMeasures = React.useRef<Record<string, number>>({});
React.useEffect(() => {
rowMeasures.current = {};
Expand All @@ -197,6 +192,10 @@ export const usePreparedTableData = (props: {
},
getScrollElement: () => tableContainerRef.current,
measureElement: (el) => {
const rowIndex = Number(el.getAttribute('data-index')) ?? -1;
const row = tableRows[rowIndex] as Row<TData>;
const rowId = row?.id ?? -1;

const getRowHeight = () => {
const cells = Array.from(el?.getElementsByTagName('td') || []);
const simpleCell = cells.find((c) => {
Expand All @@ -206,16 +205,11 @@ export const usePreparedTableData = (props: {
return simpleCell?.getBoundingClientRect()?.height ?? 0;
};

if (!enableRowGrouping) {
return getRowHeight();
if (rowId && typeof rowMeasures.current[rowId] === 'undefined') {
rowMeasures.current[rowId] = getRowHeight();
}

const rowIndex = el.getAttribute('data-index') ?? '';
if (rowIndex && typeof rowMeasures.current[rowIndex] === 'undefined') {
rowMeasures.current[rowIndex] = getRowHeight();
}

return rowMeasures.current[rowIndex];
return rowMeasures.current[rowId];
},
overscan: 100,
});
Expand Down Expand Up @@ -245,12 +239,28 @@ export const usePreparedTableData = (props: {
return colSizeRef.current ?? [];
}, [cols, tableMinWidth]);

const leftPositionsRef = React.useRef<(number | undefined)[]>([]);
const leftPositions = React.useMemo(() => {
return (headers[headers.length - 1]?.headers ?? []).map<number>((h) => {
const headData = h.column.columnDef.meta?.head;
const cellIndex = headData?.index ?? -1;
return colSizes.reduce((sum, _s, i) => (i < cellIndex ? sum + colSizes[i] : sum), 1);
});
const newValue = (headers[headers.length - 1]?.headers ?? []).map<number | undefined>(
(h) => {
const headData = h.column.columnDef.meta?.head;
if (!headData?.pinned) {
return undefined;
}

const cellIndex = headData?.index ?? -1;
return colSizes.reduce(
(sum, _s, i) => (i < cellIndex ? sum + colSizes[i] : sum),
1,
);
},
);

if (!isEqual(newValue, leftPositionsRef.current)) {
leftPositionsRef.current = newValue;
}

return leftPositionsRef.current;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [colSizes]);

Expand Down Expand Up @@ -335,7 +345,7 @@ export const usePreparedTableData = (props: {
const prevCells = new Array(tableRows[0]?.getVisibleCells()?.length);
return virtualItems.reduce<BodyRowViewData[]>((rowsAcc, virtualRow) => {
const row = tableRows[virtualRow.index] as Row<TData>;
const rowMeasuredHeight = rowMeasures.current[virtualRow.index];
const rowMeasuredHeight = rowMeasures.current[row.id];
const visibleCells = row.getVisibleCells();
const cells = visibleCells.reduce<BodyCellViewData[]>((acc, cell, index) => {
const originalHeadData = cell.column.columnDef.meta?.head;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {ColumnDef, SortingFnOption} from '@tanstack/react-table';
import {createColumnHelper} from '@tanstack/react-table';
import type {DisplayColumnDef, GroupColumnDef} from '@tanstack/table-core/build/lib/types';
import get from 'lodash/get';
import round from 'lodash/round';
import type {TableCellsRow, TableCommonCell, TableRow, TableTitle} from 'shared';

import type {TableWidgetData} from '../../../../../../types';
Expand Down Expand Up @@ -158,7 +159,7 @@ export function getTableTitle(config: TableWidgetData['config']): TableTitle | u
}

export function getTableSizes(table: HTMLTableElement) {
const tableScale = table?.getBoundingClientRect()?.width / table?.clientWidth;
const tableScale = round(table?.getBoundingClientRect()?.width / table?.clientWidth, 2);
let rows: HTMLTableRowElement[] = [];

rows = Array.from(
Expand Down

0 comments on commit 633ac23

Please sign in to comment.