Skip to content

Commit

Permalink
refactor: Change BodyRow nest to flatten strcutrue (react-component#619)
Browse files Browse the repository at this point in the history
* 扁平化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
  • Loading branch information
crawler-django authored Jun 10, 2021
1 parent f76ae82 commit e0bab69
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 54 deletions.
60 changes: 35 additions & 25 deletions docs/examples/subTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,40 @@ import React from 'react';
import Table from 'rc-table';
import '../../assets/index.less';

const data = [
{
a: 'a1',
},
{
a: 'a2',
b: 'b2',
children: [
{
a: 'a2-1',
b: 'b2-1',
},
{
a: 'a2-2',
b: 'b2-2',
},
],
},
{
a: 'a3',
c: 'c3',
d: 'd3',
},
];
const generateData = () => {
const temp = [];

for (let i = 0; i < 100; i += 1) {
temp.push({
a: i,
b: 'bbbb'.repeat(Math.floor(Math.random() * 10)),
children: [
{
a: `${i}_${i}`,
b: 'test',
children: [
{
a: `${i}_${i}_${i}`,
b: 'testtest',
},
{
a: `${i}_${i}_${i}_${i}`,
b: 'testtest',
},
{
a: `${i}_${i}_${i}_${i}_${i}`,
b: 'testtest',
},
],
},
],
});
}

return temp;
};

const data = generateData();

class Demo extends React.Component {
handleClick = (record, e) => {
Expand All @@ -52,7 +62,7 @@ class Demo extends React.Component {
return (
<div>
<h2>sub table</h2>
<Table columns={columns} data={data} rowKey={record => record.a} />
<Table columns={columns} data={data} rowKey={record => record.a} scroll={{ y: 500 }} />
</div>
);
}
Expand Down
24 changes: 0 additions & 24 deletions src/Body/BodyRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ function BodyRow<RecordType extends { children?: readonly RecordType[] }>(
record,
index,
rowKey,
getRowKey,
rowExpandable,
expandedKeys,
onRow,
Expand Down Expand Up @@ -213,33 +212,10 @@ function BodyRow<RecordType extends { children?: readonly RecordType[] }>(
);
}

// ========================= Nest Row ==========================
let nestRowNode: React.ReactElement[];
if (hasNestChildren && expanded) {
nestRowNode = (record[childrenColumnName] || []).map(
(subRecord: RecordType, subIndex: number): React.ReactElement => {
const subKey = getRowKey(subRecord, subIndex);

return (
<BodyRow
{...props}
key={subKey}
rowKey={subKey}
record={subRecord}
recordKey={subKey}
index={subIndex}
indent={indent + 1}
/>
);
},
);
}

return (
<>
{baseRowNode}
{expandRowNode}
{nestRowNode}
</>
);
}
Expand Down
26 changes: 21 additions & 5 deletions src/Body/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as React from 'react';
import BodyRow from './BodyRow';
import TableContext from '../context/TableContext';
import { GetRowKey, Key, GetComponentProps } from '../interface';
import type { GetRowKey, Key, GetComponentProps } from '../interface';
import ExpandedRow from './ExpandedRow';
import BodyContext from '../context/BodyContext';
import { getColumnsKey } from '../utils/valueUtil';
import ResizeContext from '../context/ResizeContext';
import MeasureCell from './MeasureCell';
import BodyRow from './BodyRow';
import useFlattenRecords from '../hooks/useFlattenRecords';

export interface BodyProps<RecordType> {
data: readonly RecordType[];
Expand All @@ -31,8 +32,14 @@ function Body<RecordType>({
}: BodyProps<RecordType>) {
const { onColumnResize } = React.useContext(ResizeContext);
const { prefixCls, getComponent } = React.useContext(TableContext);
const { fixHeader, horizonScroll, flattenColumns, componentWidth } = React.useContext(
BodyContext,
const { fixHeader, horizonScroll, flattenColumns, componentWidth } =
React.useContext(BodyContext);

const flattenData: { record: RecordType; indent: number }[] = useFlattenRecords<RecordType>(
data,
childrenColumnName,
expandedKeys,
getRowKey,
);

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

let rows: React.ReactNode;
if (data.length) {
rows = data.map((record, index) => {
rows = flattenData.map((item, index) => {
const { record, indent } = item;

const key = getRowKey(record, index);

return (
Expand All @@ -59,6 +68,7 @@ function Body<RecordType>({
getRowKey={getRowKey}
rowExpandable={rowExpandable}
childrenColumnName={childrenColumnName}
indent={indent}
/>
);
});
Expand Down Expand Up @@ -112,6 +122,12 @@ function Body<RecordType>({
componentWidth,
emptyNode,
flattenColumns,
childrenColumnName,
fixHeader,
horizonScroll,
onColumnResize,
rowExpandable,
flattenData,
]);
}

Expand Down
81 changes: 81 additions & 0 deletions src/hooks/useFlattenRecords.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { GetRowKey, Key } from '@/interface';
import * as React from 'react';

// recursion (flat tree structure)
function flatRecord<T>(
record: T,
indent: number,
childrenColumnName: string,
expandedKeys: Set<Key>,
getRowKey: GetRowKey<T>,
) {
const arr = [];

arr.push({
record,
indent,
});

const key = getRowKey(record);

const expanded = expandedKeys?.has(key);

if (record && Array.isArray(record[childrenColumnName]) && expanded) {
// expanded state, flat record
for (let i = 0; i < record[childrenColumnName].length; i += 1) {
const tempArr = flatRecord(
record[childrenColumnName][i],
indent + 1,
childrenColumnName,
expandedKeys,
getRowKey,
);

arr.push(...tempArr);
}
}

return arr;
}

/**
* flat tree data on expanded state
*
* @export
* @template T
* @param {*} data : table data
* @param {string} childrenColumnName : 指定树形结构的列名
* @param {Set<Key>} expandedKeys : 展开的行对应的keys
* @param {GetRowKey<T>} getRowKey : 获取当前rowKey的方法
* @returns flattened data
*/
export default function useFlattenRecords<T>(
data,
childrenColumnName: string,
expandedKeys: Set<Key>,
getRowKey: GetRowKey<T>,
) {
const arr: { record: T; indent: number }[] = React.useMemo(() => {
if (expandedKeys?.size) {
const temp: { record: T; indent: number }[] = [];

// collect flattened record
for (let i = 0; i < data?.length; i += 1) {
const record = data[i];

temp.push(...flatRecord<T>(record, 0, childrenColumnName, expandedKeys, getRowKey));
}

return temp;
}

return data?.map(item => {
return {
record: item,
indent: 0,
};
});
}, [data, childrenColumnName, expandedKeys, getRowKey]);

return arr;
}

0 comments on commit e0bab69

Please sign in to comment.