使用antd-table 在实际开发中伸缩或者展开的性能问题分析: 在面对1000+ 数据的table数据的话,直接全部伸缩或者展开的话,响应的效果一般会迟钝5000左右,针对性能分析图可以了解到,其中主要来自渲染方面就有2秒上,还有就是底层事件的调用,性能相对来说很差
- 解决方案:
-
使用高级组件react-virtual虚拟列表的处理来渲染可视区,来优化性能
-
给table一定高度,每一行的高度来滚动加载动态渲染优化性能
参考 ali-react-table:高性能 React 表格组件(zhuanlan.zhihu.com/p/130755755 )
import {
BaseTable,
collectNodes,
features,
isLeafNode,
useTablePipeline
} from "ali-react-table";
import { Dropdown, Menu } from "@alifd/next";
import React, { useState, useContext, useEffect, useRef } from "react";
import ReactDOM from "react-dom";
import * as fusion from "@alifd/next";
import styled from "styled-components";
import { Button } from "@alifd/next";
\
import { Input, Form, InputRef } from "antd";
\
const EditableContext = React.createContext(null);
\
const EditableRow = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
\
const EditableCell = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef < InputRef > null;
const form = useContext(EditableContext);
\
useEffect(() => {
if (editing) {
inputRef.current.focus();
}
}, [editing]);
\
const toggleEdit = () => {
debugger;
setEditing(!editing);
form.setFieldsValue({ [dataIndex]: record[dataIndex] });
};
\
const save = async () => {
try {
const values = await form.validateFields();
\
toggleEdit();
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log("Save failed:", errInfo);
}
};
\
let childNode = children;
\
if (editable) {
childNode = editing ? (
<Form.Item
style={{ margin: 0 }}
name={dataIndex}
rules={[
{
required: true,
message: `${title} is required.`
}
]}
>
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{ paddingRight: 24 }}
onClick={toggleEdit}
>
{children}
</div>
);
}
\
return <td {...restProps}>{childNode}</td>;
};
\
const OperationsDiv = styled.div`
display: flex;
height: 20px;
align-items: center;
\
.item {
height: 20px;
cursor: pointer;
color: #3858cf;
display: flex;
align-items: center;
\
&.danger {
color: #eb4141;
}
}
\
.sep {
height: 10px;
width: 1px;
margin-left: 12px;
margin-right: 12px;
background: #eeeeee;
}
`;
\
function renderOptions() {
return (
<OperationsDiv>
<div className="item">编辑</div>
<div className="sep" />
<div className="item danger">删除</div>
<div className="sep" />
\
<Dropdown trigger={<div className="item">更多</div>} triggerType="click">
<Menu>
<Menu.Item>Option 1</Menu.Item>
<Menu.Item>Option 2</Menu.Item>
<Menu.Item>Option 3</Menu.Item>
<Menu.Item>Option 4</Menu.Item>
</Menu>
</Dropdown>
</OperationsDiv>
);
}
\
export const operationCol = {
lock: true,
name: "操作",
render: renderOptions,
width: 200
};
\
export const dataSource = [
{
id: "1",
title: "一级标题",
dept: "消费者事业部-淘宝-UED",
dest: "South Maddison",
guide: "Don Moreno",
children: makeChildren("1")
},
{
id: "2",
title: "一级标题",
dept: "航旅事业部-酒店业务",
dest: "Emilhaven",
guide: "Douglas Richards",
children: makeChildren("2")
},
{
id: "3",
title: "一级标题",
dept: "消费者事业部-淘宝-UED",
dest: "云南大理",
guide: "Douglas Lee",
children: makeChildren("3")
},
{
id: "4",
title: "一级标题",
dept: "信息平台部-用户体验部",
dest: "杭州千岛湖",
guide: "Eric Castillo",
children: makeChildren("4")
},
{
id: "5",
title: "一级标题",
dept: "消费者事业部-淘宝-UED",
dest: "East Karl",
guide: "Herbert Patton"
}
];
\
export function makeChildren(prefix) {
return [
{
id: `${prefix}-1`,
title: "二级标题",
dept: "消费者事业部-淘宝-UED",
dest: "云南大理",
guide: "Douglas Lee",
children: [
{
id: `${prefix}-1-1`,
title: "三级标题",
dept: "盒马产品技术部-UED",
dest: "云南大理",
guide: "Douglas Lee"
},
{
id: `${prefix}-1-2`,
title: "三级标题",
dept: "盒马产品技术部-前端",
dest: "云南大理",
guide: "Douglas Lee"
}
]
},
{
id: `${prefix}-2`,
title: "二级标题",
dept: "消费者事业部-淘宝-UED",
dest: "云南大理",
guide: "Douglas Lee",
children: [
{
id: `${prefix}-2-1`,
title: "三级标题",
dept: "盒马产品技术部-UED",
dest: "云南大理",
guide: "Douglas Lee"
},
{
id: `${prefix}-2-2`,
title: "三级标题",
dept: "盒马产品技术部-前端",
dest: "云南大理",
guide: "Douglas Lee"
}
]
},
{
id: `${prefix}-3`,
title: "二级标题",
dept: "消费者事业部-淘宝-UED",
dest: "云南大理",
guide: "Douglas Lee"
}
];
}
\
function BaseAliTable() {
const [openKeys, onChangeOpenKeys] = useState(["4", "4-2"]);
\
const columns = [
{ code: "title", name: "标题", width: 200 },
{ code: "dept", name: "部门名称", width: 180, editable: true },
{ code: "dest", name: "团建目的地", width: 160 },
{ code: "guide", name: "当地导游", width: 160 },
operationCol
];
\
const pipeline = useTablePipeline({ components: fusion })
.input({ dataSource: dataSource, columns: columns })
.primaryKey("id")
.use(features.treeMode({ openKeys, onChangeOpenKeys }));
\
const allParentKeys = collectNodes(dataSource, "pre")
.filter((row) => !isLeafNode(row))
.map((row) => row.id);
\
return (
<div>
<Button.Group>
<Button onClick={() => onChangeOpenKeys(allParentKeys)}>
展开全部
</Button>
<Button onClick={() => onChangeOpenKeys([])}>收拢全部</Button>
</Button.Group>
<BaseTable
{...pipeline.getProps()}
components={{ row: EditableRow, cell: EditableCell }}
/>
</div>
);
}
ReactDOM.render(<BaseAliTable />, document.getElementById("container"));
\
编辑不行
参考: github.com/ant-design/…
这个例子会出现一些问题: 例如拿不到offsetHeight,主要原因就是row的current为空,使用bind绑定示例可以获取,另外就是编辑的body就没有办法传进去
- 进入不到body.cell设置
此时拿到的arg为[]
进入不到设置body.cell里面去,导致没有办法进行
2.拿不到offsetHeight,主要原因就是row的current为空
解决方案: 查找出区别,重写set方法,但是代码里面用的函数组件没有办法去绑定实例(主要是this指向问题导致)
antd大数据渲染
其次就是antd-table 编辑单元格,可以看antd-table 编辑单元格的例子,但是antd的例子不适用于编辑类表格
最后解决方案: 1. 可以自己手写一个虚拟列表或者分页加载,可视区的高度以及每行高度来进行判断要加载多少 2. 内部处理编辑替换单元格事件,再利用virtualizedtableforantd4事件去设置components = {vt},如果数据量较少,可以传一个标识符来判断是否进行component = {isNeedComponent ? components : vt}