Виртуальный список с разной высотой элементов | REACT
Знает кто-то, как сделать правильный виртуальный список с разной высотой элементов? react-window требует высоты элеметов, но смысл в том, что я могу узнать её только после рендера элемента.
Но мои элементы всегда имеют разную высоту и довольно тяжелы, чтобы рендерить их только для получения высоты.
Кто-то сталкивался с подобным? Я пытался через ref возвращать высоту, но в такой случае нужно ждать 5-6 секунд, прежде чем весь список отрендерится и перестанет дергаться из-за изменяющегося стейта, который содержит эти самые высоты.
Код не прикреплял, так как не вижу в этом смысла. Вопрос понятен и без него.
Ответы (1 шт):
Проблема
Библиотеки react-virtualized и react-window отвратительно реализуют виртуализацию, так как используют компонент высшего порядка <AutoSizer />. Последний использует функцию для обновления списка потомков, поэтому не только нагружает планировщик проверкой изменения height и width, но и ломает change detection композиции props в коде прикладного программиста
Однако если посмотреть на тот же Slack или Discord, там сообщения в чатах явно виртуализируются, так как при скролле показываются с задержкой. Видимо, в их кодовой базе виртуализация с динамической высотой блоков таки есть...
Вывод:
- Нужно писать свою виртуализацию. Это как базовый компонент строк в C++
- Нужно делать интероп над ванильным 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;
P.S. Если собираетесь виртуализировать список компонентов, не забудьте применить forwardRef, чтобы <VirtualList /> смог достучаться до размеров элемента DOM древа
