React Virtualized Table-约8列表中输入元素的性能问题

Asa*_*saf 12 reactjs react-virtualized

我正在尝试创建一个8列的表,每列包含一个<input />元素。由于某些原因,我在文本输入的on change事件中遇到了延迟。将列数减少到4以下可改善体验。这可能是有道理的,但是我也尝试增加列的数量,结果发现对于10个或更多的列,体验还是很棒的。您可以检查我的超级简单React应用程序,在其中可以动态更改列数-http://com.react.table-with-inputs.s3-website.eu-central-1.amazonaws.com/

这是我的代码:

import React from 'react';
import { AutoSizer, Table, Column } from 'react-virtualized';

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      numOfCols: '8',
    };
  }

  rowGetter = ({ index }) => {
    return { index };
  };

  renderHeaderCell = ({ label }) => {
    return (
      <span>{label}</span>
    );
  };

  renderCell = ({ rowIndex, columnIndex }) => {
    return (
      <input key={`input-${rowIndex}-${columnIndex}`} />
    );
  };

  render() {
    return (
      <div style={{ display: 'flex', flex: 1, flexDirection: 'column', padding: '10px' }}>
        <span>NUMBER OF COLUMNS</span>
        <input
          value={this.state.numOfCols}
          onChange={e => this.setState({ numOfCols: e.target.value })}
        />
        <br />
        <br />
        <AutoSizer style={{ flex: 1 }}>
          {({ height, width }) => (
            <Table
              width={width}
              height={height}
              estimatedRowSize={36}
              overscanRowCount={10}
              headerHeight={30}
              rowHeight={36}
              rowCount={20}
              rowGetter={this.rowGetter}
            >
              {
                (() => {
                  const cols = [];

                  for (let i = 0; i < parseInt(this.state.numOfCols); i += 1) {
                    cols.push(
                      <Column
                        label={`Title${i + 1}`}
                        dataKey={`title${i + 1}`}
                        width={120}
                        cellRenderer={this.renderCell}
                        headerRenderer={this.renderHeaderCell}
                      />
                    )
                  }

                  return cols;
                })()
              }
            </Table>
          )}
        </AutoSizer>
      </div>
    );
  }
}

export default App;

Run Code Online (Sandbox Code Playgroud)

编辑1:这仅在Chrome(Mac和Windows,台式机和移动设备)上发生。它不会在Safari或Firefox(非桌面版和移动版)上复制。

编辑2:我试图删除AutoSizer但没有任何更改。上载了可以渲染或不显示Tablewith AutoSizer容器的更新版本(http://com.react.table-with-inputs.s3-website.eu-central-1.amazonaws.com/)。

Atr*_*eur 0

我没有重现这个问题,但是我在您的代码中看到了多个点,这些点可能会在该代码中产生性能问题,所以这是我的尝试。

首先,您是否尝试过减少渲染次数?

例如,也许您的组件可以切换到 PureComponent,以便仅在状态和属性更改时重新渲染。这可以提高性能。您将需要进行广泛的测试,因为您需要检查子组件是否需要重新渲染。

删除内联样式,因为这每次都会创建一个新对象,从而破坏了 React 可以进行的所有渲染优化。如果您仍然需要 style={something} ,那么请移至something类声明之外的 const 变量,以确保一次性创建该对象。请注意,这是一种不好的做法,因此请检查代码中出现的所有其他情况。

就在那里,我至少看到两个地方 React 将重新渲染一个元素,但该元素没有改变,因为对象内容是硬编码的。

为什么要创建一个新函数然后像这样内联执行它?

更有效的方法是使用 lodash 的地图:

map(range(this.state.numOfCols), i => (<Column
  label={`Title${i + 1}`}
  dataKey={`title${i + 1}`}
  width={120}
  cellRenderer={this.renderCell}
  headerRenderer={this.renderHeaderCell}
/>))
Run Code Online (Sandbox Code Playgroud)

解决所有明显的问题后,安装一个性能包,例如https://github.com/welldone-software/why-did-you-render并检查为什么您的 App 组件渲染过多。

也许您的示例中未包含的某些代码导致组件每次都重新渲染?

编辑:重新阅读代码后,我 75% 确定问题出在 style={{ flex: 1 }} 导致完全 AutoSizer 重新渲染!