Skip to content

Commit e0bab69

Browse files
refactor: Change BodyRow nest to flatten strcutrue (#619)
* 扁平化rows, 新增NewBodyRow, 以支持树形结构的虚拟滚动. * fix: 处理eslint警告. * fix: 单元测试报错的问题. * fix: 拉取最新代码, 处理相应的单元测试. * adjust flatColumns & add virtual-tree-table example * add virtual-tree-table demo * update virtuallist-antd version to display demo better * refactor: extract useFlattenRecords hook. * remove virtuallist-antd dependence * rename NewBodyRow to BodyRow * optimize useFlattenRecords * flat useFlattenRecords options. * optimized useFlattenRecords: if expandedKeys.size empty, do not run recursion
1 parent f76ae82 commit e0bab69

File tree

4 files changed

+137
-54
lines changed

4 files changed

+137
-54
lines changed

docs/examples/subTable.tsx

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,40 @@ import React from 'react';
22
import Table from 'rc-table';
33
import '../../assets/index.less';
44

5-
const data = [
6-
{
7-
a: 'a1',
8-
},
9-
{
10-
a: 'a2',
11-
b: 'b2',
12-
children: [
13-
{
14-
a: 'a2-1',
15-
b: 'b2-1',
16-
},
17-
{
18-
a: 'a2-2',
19-
b: 'b2-2',
20-
},
21-
],
22-
},
23-
{
24-
a: 'a3',
25-
c: 'c3',
26-
d: 'd3',
27-
},
28-
];
5+
const generateData = () => {
6+
const temp = [];
7+
8+
for (let i = 0; i < 100; i += 1) {
9+
temp.push({
10+
a: i,
11+
b: 'bbbb'.repeat(Math.floor(Math.random() * 10)),
12+
children: [
13+
{
14+
a: `${i}_${i}`,
15+
b: 'test',
16+
children: [
17+
{
18+
a: `${i}_${i}_${i}`,
19+
b: 'testtest',
20+
},
21+
{
22+
a: `${i}_${i}_${i}_${i}`,
23+
b: 'testtest',
24+
},
25+
{
26+
a: `${i}_${i}_${i}_${i}_${i}`,
27+
b: 'testtest',
28+
},
29+
],
30+
},
31+
],
32+
});
33+
}
34+
35+
return temp;
36+
};
37+
38+
const data = generateData();
2939

3040
class Demo extends React.Component {
3141
handleClick = (record, e) => {
@@ -52,7 +62,7 @@ class Demo extends React.Component {
5262
return (
5363
<div>
5464
<h2>sub table</h2>
55-
<Table columns={columns} data={data} rowKey={record => record.a} />
65+
<Table columns={columns} data={data} rowKey={record => record.a} scroll={{ y: 500 }} />
5666
</div>
5767
);
5868
}

src/Body/BodyRow.tsx

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ function BodyRow<RecordType extends { children?: readonly RecordType[] }>(
3939
record,
4040
index,
4141
rowKey,
42-
getRowKey,
4342
rowExpandable,
4443
expandedKeys,
4544
onRow,
@@ -213,33 +212,10 @@ function BodyRow<RecordType extends { children?: readonly RecordType[] }>(
213212
);
214213
}
215214

216-
// ========================= Nest Row ==========================
217-
let nestRowNode: React.ReactElement[];
218-
if (hasNestChildren && expanded) {
219-
nestRowNode = (record[childrenColumnName] || []).map(
220-
(subRecord: RecordType, subIndex: number): React.ReactElement => {
221-
const subKey = getRowKey(subRecord, subIndex);
222-
223-
return (
224-
<BodyRow
225-
{...props}
226-
key={subKey}
227-
rowKey={subKey}
228-
record={subRecord}
229-
recordKey={subKey}
230-
index={subIndex}
231-
indent={indent + 1}
232-
/>
233-
);
234-
},
235-
);
236-
}
237-
238215
return (
239216
<>
240217
{baseRowNode}
241218
{expandRowNode}
242-
{nestRowNode}
243219
</>
244220
);
245221
}

src/Body/index.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import * as React from 'react';
2-
import BodyRow from './BodyRow';
32
import TableContext from '../context/TableContext';
4-
import { GetRowKey, Key, GetComponentProps } from '../interface';
3+
import type { GetRowKey, Key, GetComponentProps } from '../interface';
54
import ExpandedRow from './ExpandedRow';
65
import BodyContext from '../context/BodyContext';
76
import { getColumnsKey } from '../utils/valueUtil';
87
import ResizeContext from '../context/ResizeContext';
98
import MeasureCell from './MeasureCell';
9+
import BodyRow from './BodyRow';
10+
import useFlattenRecords from '../hooks/useFlattenRecords';
1011

1112
export interface BodyProps<RecordType> {
1213
data: readonly RecordType[];
@@ -31,8 +32,14 @@ function Body<RecordType>({
3132
}: BodyProps<RecordType>) {
3233
const { onColumnResize } = React.useContext(ResizeContext);
3334
const { prefixCls, getComponent } = React.useContext(TableContext);
34-
const { fixHeader, horizonScroll, flattenColumns, componentWidth } = React.useContext(
35-
BodyContext,
35+
const { fixHeader, horizonScroll, flattenColumns, componentWidth } =
36+
React.useContext(BodyContext);
37+
38+
const flattenData: { record: RecordType; indent: number }[] = useFlattenRecords<RecordType>(
39+
data,
40+
childrenColumnName,
41+
expandedKeys,
42+
getRowKey,
3643
);
3744

3845
return React.useMemo(() => {
@@ -42,7 +49,9 @@ function Body<RecordType>({
4249

4350
let rows: React.ReactNode;
4451
if (data.length) {
45-
rows = data.map((record, index) => {
52+
rows = flattenData.map((item, index) => {
53+
const { record, indent } = item;
54+
4655
const key = getRowKey(record, index);
4756

4857
return (
@@ -59,6 +68,7 @@ function Body<RecordType>({
5968
getRowKey={getRowKey}
6069
rowExpandable={rowExpandable}
6170
childrenColumnName={childrenColumnName}
71+
indent={indent}
6272
/>
6373
);
6474
});
@@ -112,6 +122,12 @@ function Body<RecordType>({
112122
componentWidth,
113123
emptyNode,
114124
flattenColumns,
125+
childrenColumnName,
126+
fixHeader,
127+
horizonScroll,
128+
onColumnResize,
129+
rowExpandable,
130+
flattenData,
115131
]);
116132
}
117133

src/hooks/useFlattenRecords.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import type { GetRowKey, Key } from '@/interface';
2+
import * as React from 'react';
3+
4+
// recursion (flat tree structure)
5+
function flatRecord<T>(
6+
record: T,
7+
indent: number,
8+
childrenColumnName: string,
9+
expandedKeys: Set<Key>,
10+
getRowKey: GetRowKey<T>,
11+
) {
12+
const arr = [];
13+
14+
arr.push({
15+
record,
16+
indent,
17+
});
18+
19+
const key = getRowKey(record);
20+
21+
const expanded = expandedKeys?.has(key);
22+
23+
if (record && Array.isArray(record[childrenColumnName]) && expanded) {
24+
// expanded state, flat record
25+
for (let i = 0; i < record[childrenColumnName].length; i += 1) {
26+
const tempArr = flatRecord(
27+
record[childrenColumnName][i],
28+
indent + 1,
29+
childrenColumnName,
30+
expandedKeys,
31+
getRowKey,
32+
);
33+
34+
arr.push(...tempArr);
35+
}
36+
}
37+
38+
return arr;
39+
}
40+
41+
/**
42+
* flat tree data on expanded state
43+
*
44+
* @export
45+
* @template T
46+
* @param {*} data : table data
47+
* @param {string} childrenColumnName : 指定树形结构的列名
48+
* @param {Set<Key>} expandedKeys : 展开的行对应的keys
49+
* @param {GetRowKey<T>} getRowKey : 获取当前rowKey的方法
50+
* @returns flattened data
51+
*/
52+
export default function useFlattenRecords<T>(
53+
data,
54+
childrenColumnName: string,
55+
expandedKeys: Set<Key>,
56+
getRowKey: GetRowKey<T>,
57+
) {
58+
const arr: { record: T; indent: number }[] = React.useMemo(() => {
59+
if (expandedKeys?.size) {
60+
const temp: { record: T; indent: number }[] = [];
61+
62+
// collect flattened record
63+
for (let i = 0; i < data?.length; i += 1) {
64+
const record = data[i];
65+
66+
temp.push(...flatRecord<T>(record, 0, childrenColumnName, expandedKeys, getRowKey));
67+
}
68+
69+
return temp;
70+
}
71+
72+
return data?.map(item => {
73+
return {
74+
record: item,
75+
indent: 0,
76+
};
77+
});
78+
}, [data, childrenColumnName, expandedKeys, getRowKey]);
79+
80+
return arr;
81+
}

0 commit comments

Comments
 (0)