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

🧐[问题]: 请问 ProFormList 数据结构化的数据多了之后,有什么优化渲染的办法吗?

Open Yilun-Sun opened this issue 3 years ago • 3 comments

🧐 问题描述

ProFormList 数据结构化中,当数据条目多了之后,每次增删改都很卡顿,有什么优化渲染的办法吗?

例: 每一条 Item 是个对象 -(包含两个字符串类型字段,两个 number 类型字段,一个 number[] 类型字段)。 当条目增加到 20-30 的时候,每次增加一条新内容都需要大约 400 ms。

image

如图,每次增加一条数据的时候,会令整个 ProFormList 下的所有 Item 都重新渲染,一条平均 10ms,30 条加上其他的渲染就导致总渲染时间飙升到 400ms 左右。

下方的示例代码是我在项目中实际应用的,请帮忙看下是否是因为我使用的不对造成的渲染性能问题。如果不是,烦请提供一些解决办法,万分感谢!

💻 示例代码

<ProFormList
  name="..."
  label="..."
  creatorButtonProps={{
    creatorButtonText: '添加实例',
    position: 'top',
  }}
  deleteIconProps={{
    tooltipText: '不需要这行了',
  }}
  creatorRecord={() => {}}
  copyIconProps={false}
>
  <ProFormGroup key="...">
    <ProFormSelect
      name="..."
      label="..."
      width="sm"
      options={options}
      rules={[{ required: true, message: '' }]}
      showSearch
      fieldProps={{
        filterOption: (input, option) => {
          return !!option?.value?.toString().includes(input)
        },
      }}
      placeholder="搜索"
    />
    <ProFormDependency name={['a']}>
      {({ a }) => {
        const disabled = a === undefined
        return (
          <ProFormFieldSet
            name="..."
            label="..."
            // 支持 两种方式,type="group" 会用input.group 包裹
            // 如果不配置 默认使用 space
            type="group"
            rules={[
              {
                validator: (_, value) => {
                  if (value[0] !== '' || value[1].length > 0) {
                    return Promise.resolve()
                  } else {
                    return Promise.reject('...')
                  }
                },
              },
            ]}
            tooltip="..."
          >
            <ProFormSelect
              width="xs"
              disabled={disabled}
              options={disabled ? [] : b(a)}
              fieldProps={{
                dropdownMatchSelectWidth: 200,
              }}
            />
            <ProFormText width="xs" disabled={disabled} />
          </ProFormFieldSet>
        )
      }}
    </ProFormDependency>
    <ProFormDependency name={['a']}>
      {({ a }) => {
        const disabled = a === undefined
        return (
          <ProFormSelect
            name="..."
            label="..."
            width="sm"
            options={c(a)}
            rules={[
              {
                required: true,
                message: '...',
              },
            ]}
            disabled={disabled}
          />
        )
      }}
    </ProFormDependency>
    <ProFormDependency name={['...']}>
      {({ a }) => {
        const disabled = a === undefined
        return (
          <ProFormSelect
            name="..."
            label="..."
            width="sm"
            fieldProps={{ mode: 'multiple' }}
            options={d(a)}
            disabled={disabled}
          />
        )
      }}
    </ProFormDependency>
  </ProFormGroup>
</ProFormList>

🚑 其他信息

Yilun-Sun avatar Aug 19 '22 10:08 Yilun-Sun

ProFormDependency 依赖就会这样,要不搞个分页?

chenshuai2144 avatar Aug 25 '22 07:08 chenshuai2144

ProFormDependency 依赖就会这样,要不搞个分页?

当依赖改变的时候,ProFormDependency 的重新渲染是正常的,这不就是他的功能嘛,我觉得没问题。我遇到的难点是无法给 ProFormList 加入虚拟列表(加虚拟列表的原因是数据量可能会很多,且每一行的组件可能会很重)。 因为不像 Form.List,ProFormList 目前没有一种可以把全部子项目包裹起来的方法。数据结构化的写法导致内部只需要写子项目的数据结构,类似

<ProFormList >
    <ProFormSelect />
</ProFormList >

而做不到类似

<ProFormList >
    <VirtualizedList >
        {() => <ProFormSelect />}    // some VirtualizedList item renderer
    </VirtualizedList>
</ProFormList >

但是看 Form.List 的话就可以

<FormList>
        {(
          fields,
          { add: addAction, remove: removeAction},
        ) => {
          return (
            <WindowScroller>
              {({ height }) => (
                <AutoSizer disableHeight>
                  {({ width }) => {
                    return (
                      <VariableSizeList
                        width={width}
                        height={height}
                        itemCount={fields.length}
                        itemData={{
                          fields,
                          addAction,
                          removeAction
                        }}
                      >
                        {Row}     // some Form.Item renderer
                      </VariableSizeList>
                    )
                  }}
                </AutoSizer>
              )}
            </WindowScroller>
          )
        }}
      </FormList>

造成这种差异的原因是,ProFormList 的 children 是一路直接传给 ProFormListItem,在 ProFormListItem 内部处理后作为 ProFormListItem 自己的 childern 使用。而 Form.List 的 children 是需要用户去自定义 Form.Item。

@chenshuai2144 有什么好的解决办法嘛,还是挺想用 ProFormList,不考虑渲染性能的话的确很好用。

Yilun-Sun avatar Aug 26 '22 03:08 Yilun-Sun

ProFormDependency可以依赖多个表单项么

werrtyuiu avatar Oct 20 '22 06:10 werrtyuiu

TAutomatically replying with ChatGPT can be attempted, but it cannot be guaranteed to be completely accurate and may not fully address all issues. Please feel free to reply if you have any further questions or concerns. 此回复基于 ChatGPT 自动生成,可以尝试下方案,官方员会在一定时间后继续继续处理。

ProFormDependency可以依赖多个表单项,只需要将多个表单项组成一个数组即可。

例如:

<ProFormDependency name={['a', 'b']}>
  {({ a, b }) => (
    <ProFormSelect
      name="c"
      label="依赖多个表单项"
      options={
        a === 'x' && b === 'y'
          ? [
              {
                label: 'a为x,b为y才显示该选项',
                value: 'value',
              },
            ]
          : []
      }
    />
  )}
</ProFormDependency>

当a,b中任意一个表单项的值发生变化时,该依赖都会重新渲染。依据业务自己组合a和b的值和显示和隐藏规则即可,不过请注意在表单过多的情况下可能会导致性能问题,需要谨慎使用。

chenshuai2144 avatar Mar 06 '23 10:03 chenshuai2144

ProFormList数据上千条,分页该怎么做啊

Better-yang avatar Jun 27 '23 10:06 Better-yang

推荐换成数据表或者自己封装组件 memo 一下,优化难度太大了

chenshuai2144 avatar Jul 14 '23 06:07 chenshuai2144