pro-components icon indicating copy to clipboard operation
pro-components copied to clipboard

👑 [需求]EditableProTable 受控模式下性能严重下降改善建议

Open MeteorsLiu opened this issue 1 year ago • 3 comments

提问前先看看:

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 avatar Aug 26 '24 11:08 MeteorsLiu

@MeteorsLiu bro,能搞个完整的 sandbox 抄下作业么,性能问题也困扰我许久。

ryanxc1107 avatar Aug 28 '24 02:08 ryanxc1107

大佬,借我抄抄好吗,被这个性能问题困惑了一周

WilliamMidWang avatar Sep 02 '24 08:09 WilliamMidWang

大佬,借我抄抄好吗,被这个性能问题困惑了一周

有空会写的

MeteorsLiu avatar Sep 03 '24 08:09 MeteorsLiu