Виртуальный список с разной высотой элементов | REACT

Знает кто-то, как сделать правильный виртуальный список с разной высотой элементов? react-window требует высоты элеметов, но смысл в том, что я могу узнать её только после рендера элемента.

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

Кто-то сталкивался с подобным? Я пытался через ref возвращать высоту, но в такой случае нужно ждать 5-6 секунд, прежде чем весь список отрендерится и перестанет дергаться из-за изменяющегося стейта, который содержит эти самые высоты.

Код не прикреплял, так как не вижу в этом смысла. Вопрос понятен и без него.


Ответы (1 шт):

Автор решения: Трипольский Пётр

Проблема

Библиотеки react-virtualized и react-window отвратительно реализуют виртуализацию, так как используют компонент высшего порядка <AutoSizer />. Последний использует функцию для обновления списка потомков, поэтому не только нагружает планировщик проверкой изменения height и width, но и ломает change detection композиции props в коде прикладного программиста

Однако если посмотреть на тот же Slack или Discord, там сообщения в чатах явно виртуализируются, так как при скролле показываются с задержкой. Видимо, в их кодовой базе виртуализация с динамической высотой блоков таки есть...

Вывод:

  1. Нужно писать свою виртуализацию. Это как базовый компонент строк в C++
  2. Нужно делать интероп над ванильным JavaScript кодом, так как этот код высоконагружен и абстракция react для него слишком тормозная

Решение проблемы

Разумеется, вы не первый, кто наткнулся на проблему, поэтому, делюсь своим решением. Посмотреть демо можно по ссылке

import React from "react";

import { VirtualView } from "react-declarative";

import mock from "./mock";

export const App = () => (
  <VirtualView
    sx={{
      height: "100vh",
      width: "100vw"
    }}
  >
    {mock.map(({ id, content }, idx) => (
      <div key={id}>
        <p>
          <b>Item {idx + 1}</b>
        </p>
        <span>{content || "Content empty"}</span>
      </div>
    ))}
  </VirtualView>
);

export default App;

screenshot

Код компонента на GitHub

P.S. Если собираетесь виртуализировать список компонентов, не забудьте применить forwardRef, чтобы <VirtualList /> смог достучаться до размеров элемента DOM древа

→ Ссылка