👑 [需求]EditableProTable 受控模式下性能严重下降改善建议
提问前先看看:
https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md
🔩 所属模块或组件
EditableProTable
🥰 需求描述
EditableProTable受控模式一直存在性能问题,当同时编辑的元素太多,就会疯狂卡顿
见issue:https://github.com/ant-design/pro-components/issues/7974
并且官方没有推出的优化方案
⛰ 功能需求适用场景
改善EditableProTable在大量同时编辑的数据速度
🧐 解决方案
思路: 取消受控模式,并且利用useEffect和formRef进行state同步,并打开虚拟列表
举例:简单的受控模式
<EditableProTable
controlled
value={data}
columns={columns}
rowKey={(record) => record.id}
recordCreatorProps={false}
onChange={setData}
toolBarRender={toolBar}
editable={{
type: 'multiple',
editableKeys: info.keys,
actionRender: (row, config, defaultDoms) => {
return [defaultDoms.delete];
},
onValuesChange: (_, list) => setData(list),
onChange: (editableKeys: React.Key[], editableRows: any) => {
console.log('change', editableKeys, editableRows);
},
}}
/>
首先要解决外部修改data的情况,
可以考虑使用useEffect + fast-deep-equal + formRef
这个原因是避免一次性更新全部,仅更新不同的(shouldUpdate,但是shouldUpdate无法应用与EditableProTable),导致巨量重渲染
useEffect(() => {
if (editorFormRef.current) {
data
.filter((v) => !equal(editorFormRef.current?.getRowData!(v.id), v))
.forEach((e) => {
editorFormRef.current?.setRowData!(e.id, e);
});
}
}, [data]);
EditablePro代码修改为:
<EditableProTable
editableFormRef={editorFormRef}
value={dataSource}
virtual={true}
columns={columns}
rowKey={(record) => record.id}
recordCreatorProps={false}
// 非受控模式下没用
//onChange={setDataSource}
toolBarRender={toolBar}
editable={{
type: 'multiple',
editableKeys: info.keys,
actionRender: (row, config, defaultDoms) => {
return [defaultDoms.delete];
},
onValuesChange: (_, list) => setData(list),,
onChange: (editableKeys: React.Key[], editableRows: any) => {
console.log('change', editableKeys, editableRows);
},
}}
/>
但是这样有个问题,用户在EditableProTable输入也会触发比对,这会造成bug,因此加上一个ref检测,排除掉用户输入情况
// 是否打开data同步,默认打开,但是当用户自己输入的时候关闭,避免产生不必要的重渲染
const triggerSync = useRef(true);
useEffect(() => {
if (editorFormRef.current && triggerSync.current) {
dataSource
.filter((v) => !equal(editorFormRef.current?.getRowData!(v.id), v))
.forEach((e) => {
editorFormRef.current?.setRowData!(e.id, e);
});
}
// 用户关闭,再次打开,ref不会触发重渲染,所以修改ref无所谓
triggerSync.current = true;
}, [dataSource]);
// 高频渲染函数,用useCallback提升下性能
const valueChange = useCallback((_: any, recordList: any[]) => {
triggerSync.current = false;
setData(recordList);
// 此时data正在等待队列,页面还未重渲染
// 我们应该在useEffect里面等待react重渲染后重新打开同步
// 而不是现在
}, []);
<EditableProTable
editableFormRef={editorFormRef}
value={dataSource}
virtual={true}
columns={columns}
rowKey={(record) => record.id}
recordCreatorProps={false}
// 非受控模式下没用
//onChange={setDataSource}
toolBarRender={toolBar}
editable={{
type: 'multiple',
editableKeys: info.keys,
actionRender: (row, config, defaultDoms) => {
return [defaultDoms.delete];
},
onValuesChange: valueChange ,
onChange: (editableKeys: React.Key[], editableRows: any) => {
console.log('change', editableKeys, editableRows);
},
}}
/>
在优化后,数千行同时编辑+实时保存变得很流畅,希望能给遇到这个问题一些解决方案
@MeteorsLiu bro,能搞个完整的 sandbox 抄下作业么,性能问题也困扰我许久。
大佬,借我抄抄好吗,被这个性能问题困惑了一周
大佬,借我抄抄好吗,被这个性能问题困惑了一周
有空会写的