问题:
依赖expandedRowRender渲染嵌套表单,有多条数据可能会请求n次嵌套表单的数据,点击操作,若是页面更新,又会再次请求n次,并且页面会有卡顿闪烁问题。
问题产生的原因
个人感觉:expandedRowRender被触发的原因可能就是动态数据渲染的更新产生。
解决思路
不要依赖expandedRowRender做异步请求,而是只是做页面展示。
主要涉及的属性
- expandedRowKeys(展开的行,控制属性【格外用法:可以用在刷新展示,自动扩展更新异步嵌套表单数据】),
- onExpand(点击展开图标时触发【用于异步请求】),
- onExpandedRowsChange(展开的行变化时触发【对expandedRowKeys数据实时更新】)
- dataSource(展示表单数据)
思路:点击有加号的图表,请求异步嵌套表单数据,把数据存储为该条数据的mychildren字段上,更新表格dataSource的数据,其实就会触发expandedRowRender更新渲染。【注释:字段设置不要为children,ProTable会出问题】
实现
1. 所需设置的数据
//当前所有点击扩展的数据的key集合(一般是id)。
const [expandedRowKeys, setExpandedRowKeys] = useState<React.Key[]>([]);
// 表格总数据
const [tableData, setTableData] = useState<API.ProjectListItem[]>([]);
2. 把异步数据存在父节点数据中,一般有多层,就写了一个方法
const addChildrenToTreeNode = (tree: API.ProjectListItem[], targetId: string, childrenData: API.ProjectListItem[] | null) => {
function traverseAndModify(node: API.ProjectListItem) {
if (node.id === targetId) {
node.mychildren = childrenData;
return true;
}
// 如果节点有子节点,递归搜索每一个子节点
if (node.mychildren) {
for (let child of node.mychildren) {
if (traverseAndModify(child)) {
return true;
}
}
}
return false;
}
const newThree = JSON.parse(JSON.stringify(tree));
// 开始递归遍历树
newThree.forEach(traverseAndModify);
// 返回修改后的树
return newThree;
}
3. 点击展开按钮时,去请求异步数据,并保存在总数据中
const onExpand = async (expanded: boolean, record: any) => {
// record.hasChild 这个是判断他是否有子集的。
if (expanded && record.hasChild) {
const { data } = await listProject({ id: record.id })
const tree = addChildrenToTreeNode(tableData, record.id, data);
setTableData(tree)
} else {
const tree = addChildrenToTreeNode(tableData, record.id, null);
setTableData(tree)
}
}
4. 渲染嵌套表格
const ExpandedRowRender: React.FC<{ value: any, expanded?: boolean; }> = ({ value, expanded }) => {
if (expanded && value?.mychildren?.length > 0 && value.hasChild) {
return (
<ProTable
rowKey="id"
columns={columns}
headerTitle={false}
search={false}
expandable={{
expandedRowKeys: expandedRowKeys,
onExpand: (expanded, record) => { onExpand(expanded, record) },
onExpandedRowsChange: (expandedRows) => {
setExpandedRowKeys(expandedRows as string[]);
},
expandedRowRender: (record, _, __, expanded) => <ExpandedRowRender value={record} expanded={expanded} />,
rowExpandable: (record) => record?.hasChild || false,
}}
options={false}
dataSource={value?.mychildren}
pagination={false}
/>
)
} else {
return null;
}
};
5. 最后一步展示
<ProTable<API.ProjectListItem, API.ProjectListParams>
headerTitle={'项目列表'}
actionRef={actionRef}
rowKey="id"
search={{ labelWidth: 120 }}
pagination={{
pageSize: 10,
}}
dataSource={tableData}
expandable={{
expandedRowKeys: expandedRowKeys,
onExpand: (expanded, record) => { onExpand(expanded, record) },
onExpandedRowsChange: (expandedRows) => {
setExpandedRowKeys(expandedRows as string[]);
},
expandedRowRender: (record, _, __, expanded) => <ExpandedRowRender value={record} expanded={expanded} />,
rowExpandable: (record) => record?.hasChild || false,
}}
toolBarRender={() => [
<Button><PlusOutlined /> 新建</Button>
]}
request={async (params) => {
const data = await pageProject(params);
setTableData(data.data);
setExpandedRowKeys([]); // 这一步很关键,记得清空
return data;
}}
columns={columns}
/>