Skip to content

Commit

Permalink
perf(Table): improved rendering of scrollbars (#340)
Browse files Browse the repository at this point in the history
  • Loading branch information
simonguo authored Apr 20, 2022
1 parent eb72fbb commit 2b04ada
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 44 deletions.
34 changes: 28 additions & 6 deletions docs/md/AutoHeightTable.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,40 @@
```js
const App = () => {
const [size, setSize] = React.useState(fakeData.length);
const handleChange = event => {
const value = event.target.value;
setSize(value);
};
const [autoHeight, setAutoHeight] = React.useState(false);

const data = fakeData.filter((item, index) => index < size);
return (
<div>
size: <input type="text" onChange={handleChange} value={size} />
<Stack spacing={10} divider={<Divider vertical />}>
<span>
<Checkbox
checked={autoHeight}
onChange={(_v, checked) => {
setAutoHeight(checked);
}}
>
autoHeight
</Checkbox>
</span>

<span>
Size:{' '}
<Input
type="text"
style={{ width: 100, display: 'inline-block' }}
onChange={setSize}
value={size}
/>{' '}
rem
</span>
</Stack>
<hr />

<Table
height={400}
autoHeight
autoHeight={autoHeight}
cellBordered
data={data}
onRowClick={data => {
console.log(data);
Expand Down
1 change: 1 addition & 0 deletions docs/md/FixedColumnTable.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const App = () => {
height={400}
data={data}
onScroll={handleScroll}
cellBordered
onRowClick={data => {
console.log(data);
}}
Expand Down
5 changes: 5 additions & 0 deletions docs/md/RowspanTable.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const App = () => {
bordered
cellBordered
height={400}
autoHeight
data={fakeDataForRowSpan}
onRowClick={data => {
console.log(data);
Expand Down Expand Up @@ -62,6 +63,10 @@ const App = () => {
<HeaderCell>Company Name</HeaderCell>
<Cell dataKey="companyName" />
</Column>
<Column width={60} fixed="right">
<HeaderCell>id</HeaderCell>
<Cell dataKey="id" />
</Column>
</Table>
);
};
Expand Down
2 changes: 1 addition & 1 deletion docs/md/Virtualized.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const LargeListsTable = () => {
<Cell dataKey="street" />
</Column>

<Column minWidth={200} flexGrow={1}>
<Column width={200}>
<HeaderCell>Company Name</HeaderCell>
<Cell dataKey="companyName" />
</Column>
Expand Down
7 changes: 1 addition & 6 deletions src/Scrollbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,7 @@ const Scrollbar = React.forwardRef((props: ScrollbarProps, ref) => {
const { withClassPrefix, merge, prefix } = useClassNames(classPrefix);
const classes = merge(
className,
withClassPrefix({
vertical,
horizontal: !vertical,
hide: scrollLength <= length,
pressed: handlePressed
}),
withClassPrefix({ vertical, horizontal: !vertical, pressed: handlePressed }),
// keep the 'fixed' class name if it has already been given by useAffix hook
barRef.current?.classList.contains('fixed') && 'fixed'
);
Expand Down
70 changes: 47 additions & 23 deletions src/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,13 @@ const Table = React.forwardRef((props: TableProps, ref) => {

const rowWidth = allColumnsWidth > tableWidth.current ? allColumnsWidth : tableWidth.current;

// Whether to show vertical scroll bar
const hasVerticalScrollbar =
!autoHeight && contentHeight.current > getTableHeight() - headerHeight;

// Whether to show the horizontal scroll bar
const hasHorizontalScrollbar = contentWidth.current > tableWidth.current;

const classes = mergeCls(
className,
withClassPrefix({
Expand Down Expand Up @@ -619,6 +626,10 @@ const Table = React.forwardRef((props: TableProps, ref) => {
}
}

if (hasVerticalScrollbar && fixedRightCellGroupWidth) {
fixedRightCellGroupWidth += SCROLLBAR_WIDTH;
}

rowNode = (
<>
{fixedLeftCellGroupWidth ? (
Expand All @@ -642,12 +653,14 @@ const Table = React.forwardRef((props: TableProps, ref) => {
style={
rtl
? { right: 0 - rowRight }
: { left: tableWidth.current - fixedRightCellGroupWidth - SCROLLBAR_WIDTH }
: { left: tableWidth.current - fixedRightCellGroupWidth }
}
height={props.isHeaderRow ? props.headerHeight : props.height}
width={fixedRightCellGroupWidth + SCROLLBAR_WIDTH}
width={fixedRightCellGroupWidth}
>
{mergeCells(resetLeftForCells(fixedRightCells, SCROLLBAR_WIDTH))}
{mergeCells(
resetLeftForCells(fixedRightCells, hasVerticalScrollbar ? SCROLLBAR_WIDTH : 0)
)}
</CellGroup>
) : null}

Expand Down Expand Up @@ -848,26 +861,37 @@ const Table = React.forwardRef((props: TableProps, ref) => {
return null;
}

return [
<Scrollbar
key="scrollbar"
tableId={id}
style={{ width: tableWidth.current }}
length={tableWidth.current}
onScroll={onScrollHorizontal}
scrollLength={contentWidth.current}
ref={scrollbarXRef}
/>,
<Scrollbar
key="vertical-scrollbar"
vertical
tableId={id}
length={height - headerHeight}
scrollLength={contentHeight.current}
onScroll={onScrollVertical}
ref={scrollbarYRef}
/>
];
const scrollbars: React.ReactNode[] = [];

if (hasHorizontalScrollbar) {
scrollbars.push(
<Scrollbar
key="scrollbar"
tableId={id}
style={{ width: tableWidth.current }}
length={tableWidth.current}
onScroll={onScrollHorizontal}
scrollLength={contentWidth.current}
ref={scrollbarXRef}
/>
);
}

if (hasVerticalScrollbar) {
scrollbars.push(
<Scrollbar
vertical
key="vertical-scrollbar"
tableId={id}
length={height - headerHeight}
onScroll={onScrollVertical}
scrollLength={contentHeight.current}
ref={scrollbarYRef}
/>
);
}

return scrollbars;
};

const renderTableBody = (bodyCells: any[], rowWidth: number) => {
Expand Down
8 changes: 3 additions & 5 deletions src/less/table.less
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@

&-cell {
height: 36px;
border-style: solid;
border-width: 0;
border-color: @border-color;
border-bottom: 1px solid #eee;
display: block;
overflow: hidden;
position: absolute;
Expand All @@ -105,7 +103,7 @@
}
&-content {
padding: 8px;
border-bottom: 1px solid #eee;

.ellipsis();
}

Expand Down Expand Up @@ -159,7 +157,7 @@
z-index: 6;
}

&-cell-bordered &-cell-content {
&-cell-bordered &-cell {
border-right: 1px solid #eee;
}

Expand Down
18 changes: 15 additions & 3 deletions test/TableSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ describe('Table', () => {
const ref = React.createRef();

render(
<Table ref={ref} isTree data={data} showHeader={false} rowKey="name">
<Table ref={ref} isTree data={data} showHeader={false} rowKey="name" height={100}>
<Column>
<HeaderCell>name</HeaderCell>
<Cell dataKey="name" />
Expand All @@ -811,15 +811,15 @@ describe('Table', () => {

// Before the Tree expands, it displays 1 row without vertical scroll bar.
assert.equal(table.querySelectorAll('.rs-table-row').length, 1);
assert.isNotNull(table.querySelector('.rs-table-scrollbar-vertical.rs-table-scrollbar-hide'));
assert.isNull(table.querySelector('.rs-table-scrollbar-vertical'));

act(() => {
Simulate.click(expand);
});

// After the Tree is expanded, 10 rows are displayed and a vertical scroll bar is displayed at the same time.
assert.equal(table.querySelectorAll('.rs-table-row').length, 10);
assert.isNull(table.querySelector('.rs-table-scrollbar-vertical.rs-table-scrollbar-hide'));
assert.isNotNull(table.querySelector('.rs-table-scrollbar-vertical'));
});

it('Should render 2 ColumnGroup', () => {
Expand Down Expand Up @@ -1538,4 +1538,16 @@ describe('Table', () => {
assert.equal(onScrollSpy.secondCall.firstArg, 'heightChanged');
assert.equal(instance.table.style.height, '400px');
});

it('Should not render scrollbars', () => {
const instance = getDOMNode(
<Table data={[{ name: 'name' }]} rowKey="name" height={100}>
<Column>
<HeaderCell>name</HeaderCell>
<Cell dataKey="name" />
</Column>
</Table>
);
assert.isNull(instance.querySelector('.rs-table-scrollbar'));
});
});

0 comments on commit 2b04ada

Please sign in to comment.