Как React отображает большие списки?

Mac Chrome Windows React.js
Как React отображает большие списки?

Мы часто сталкиваемся с необходимостью отображать списки на основе данных. Вы, вероятно, делали такой код сотни тысяч раз.

Но если вам нужно отображать тысячи фрагментов данных одновременно, это неизбежно приведет к зависанию браузера, пропуску кадров или даже зависанию.

В этой статье будет представлено использованиеreact-virtualizedдля эффективного отображения больших списков данных.

Давайте начнем!

Сначала создайте приложение React

create-react-app virtualization

Приложение отобразит 1000 комментариев следующим образом:

Внедряем сторонние библиотекиlorem-ipsumдля создания фиктивных данных:

cd virtualization

npm install --save lorem-ipsum

существуетsrc/App.jsвведен вlorem-ipsum:

import loremIpsum from 'lorem-ipsum';

Затем создайте массив из 1000 элементов данных:

const rowCount = 1000;

class App extends Component {
  constructor() {
    super();
    this.list = Array(rowCount).fill().map((val, idx) => {
      return {
        id: idx, 
        name: 'John Doe',
        image: 'http://via.placeholder.com/40',
        text: loremIpsum({
          count: 1, 
          units: 'sentences',
          sentenceLowerBound: 4,
          sentenceUpperBound: 8 
        })
      }
    });
  }
  //...
}

Каждая из приведенных выше данных содержитid,用户名,图片,随机生成4~8个字评论.

существуетrender()Используйте этот массив в:

render() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <h1 className="App-title">Welcome to React</h1>
      </header>
      <div className="list">
        {this.list.map(this.renderRow.bind(this))}
      </div>
    </div>
  );
}

УвеличиватьrenderRow()для создания столбцов:

renderRow(item) {
  return (
    <div key={item.id} className="row">
      <div className="image">
        <img src={item.image} alt="" />
      </div>
      <div className="content">
        <div>{item.name}</div>
        <div>{item.text}</div>
      </div>
    </div>
  );
}

существуетsrc/App.cssДобавить точечный стиль:

.list {
  padding: 10px;
}

.row { 
  border-bottom: 1px solid #ebeced;
  text-align: left;
  margin: 5px 0;
  display: flex;
  align-items: center;
}

.image {
  margin-right: 10px;
}

.content {
  padding: 10px;
}

Хорошо, запускаем проектyarn startВы можете увидеть следующий экран:

Вид на элементы, мы можем видетьDOMЗагружено многоdiv:

Проверим производительность

Если вы используете Chrome, всего несколько шагов, чтобы быстро проверить производительность:

  • Открытые инструменты разработчика
  • Нажмите Command+Shift+P (Mac) или Control+Shift+P (Windows, Linux), чтобы открыть меню команд.
  • войтиrender, выберите из раскрывающегося спискаShow Rendering.
  • нажмитеrenderзакладка,FPS MeterОтметьте перед.
  • список прокрутки

Мы видим, что частота кадров падает с 60 до примерно 38 по мере прокрутки полосы прокрутки. Это все равно всего 1000 штук данных.Если данные увеличить, то браузер зависнет или вообще зависнет.

Давайте взглянемreact-virtualizedКак это улучшает производительность?

react-virtualizedпринцип

Основной принцип: визуализируйте только то, что видите.

Вышеупомянутое приложение отображает 1000 комментариев, но на экране отображается только 10 или около того фрагментов данных, поэтому рендеринг остальных 990 — пустая трата времени.

Если мы отображаем только видимые комментарии, когда мышь прокручивается, чтобы увидеть больше, новые узлы заменяют старые. Это прекрасно решает проблему узких мест производительности.

Как это использовать?

первый вsrc/App.jsв, импортListКомпоненты:

import { List } from "react-virtualized";

заменятьrender()Оригинальный код:

<div className="list">

  {this.list.map(this.renderRow.bind(this))}

</div>

использоватьListкомпоненты

const listHeight = 600;

const rowHeight = 50;

const rowWidth = 800;

//...

<div className="list">

  <List

    width={rowWidth}

    height={listHeight}

    rowHeight={rowHeight}

    rowRenderer={this.renderRow.bind(this)}

    rowCount={this.list.length} />

</div>

переписатьrenderRow():

renderRow({ index, key, style }) {
  return (
    <div key={key} style={style} className="row">
      <div className="image">
        <img src={this.list[index].image} alt="" />
      </div>
      <div className="content">
        <div>{this.list[index].name}</div>
        <div>{this.list[index].text}</div>
      </div>
    </div>
  );
}

запустить приложениеyarn start:

Элементы просмотра:

Вы можете видеть, что отображаются только видимые элементы.

Как производительность?

Протестируйте тем же методом, что и выше:

Видно, что она в основном держится на уровне около 60 кадров. Отличное выступление (^_^)

Вышеупомянутое простоreact-virtualizedПростое приложение, вы можете попробовать, если вы заинтересованы!

Спасибо за прочтение!

Эта статья переведена сEsteban HerreraизRendering large lists with React Virtualized