Мы столкнулись с медленным рендерингом списков, состоящих из 200+ элементов в проекте на ReactJS (15.1.0) + react-router + redux.
К примеру, есть список пользователей, который представляет собой статические "карточки", т.е. блок с фото, парой ссылок и небольшим текстом. Пользователей много, поэтому при монтировании компонента отображаются первые 30, а остальные по 30 подгружаются c api-сервера по запросу (т.е. по кнопке "показать еще"). Каждая такая карточка это статический компонент, shouldComponentUpdate() которого всегда возвращает false. Компонент списка подписан на обновления через connect() и отрисовывает карточки только если получены новые 30. Пока все хорошо и по мере загрузки данных с бэкенда и отрисовки карточек скорость рендеринга остается стабильной - судя по данным Perf происходит рендеринг только новых 30 экземпляров компонента карточки с общим временем порядка 80-90мс.
Проблема появляется тогда, когда после загрузки относительно небольшого списка (уже от 200-300 карточек) пользователь переходит по ссылке в карточке (компонент Link из react-router), а потом возвращается назад по кнопке браузера.
В этом случае компонент списка заново монтируется и ему приходится перерисовывать сразу все те 200-300 карточек, находящихся в state редакса. При этом скорость рендеринга падает пропорционально кол-ву карточек, т.е. практически в 10 раз, и если на десктопе это терпимо, то для мобильного пользователя время перерисовки страницы составляет 5+ секунд. И это при относительно небольшом кол-ве данных. Кроме того, все приложение (как и, например, redux dev tools в этот момент) "замерзает", т.е. нет возможности как-то отображать, к примеру, индикатор прогресса рендеринга.
Вопрос в следующем - нормальное ли это время рендеринга для реакта при таких условиях? Если да, то какие могут быть способы решения проблемы?
Есть ли возможность каким-либо образом кешировать результаты рендеринга смонтированного ранее компонента? Какие вообще существуют варианты решения проблемы длинных списков, если размер элемента заранее неизвестен?
Уточню проблему - реакт медленно рендерит статический список из нескольких тысяч html элементов - т.е. обычную статику типа some textanother text. Прямая вставка в DOM в десятки раз быстрее.
Спасибо, но все решения такого рода не подойдут - не известна высота блоков, т.к. там может быть разное кол-во текста и разная высота фото. Кроме того, список строится в виде masonry layout, что еще больше усложняет задачу расчета высоты плейсхолдеров.
хм, мне кажется зря игнорите решения "такого рода", особенно при подгрузке в бесконечный скролл
вот есть интересное - элементы разной высоты, да и вообще хоть в шахматном порядке
последний пример 99.999.999 !!! элементов devblog.orgsync.com/react-list (первые два пропустите - там просто подгрузка в конец)
остальные как раз по вашей теме...
да и код бы выложили на фидле какой, глядишь и дело бы быстрей пошло, вдруг у вас где нить запятая не в том месте стоит (ну эт так - к примеру)
Спасибо, посмотрю еще раз. Тестовый код - https://jsfiddle.net/86e855mh/ Скорость рендеринга падает пропорционально сложности верстки, кроме того, по Timeline цифры в несколько раз больше, чем console.time(). На чистом js рендеринг в ~5 раз быстрее. Но, судя по всему, это то, как работает реакт...
пока тока цифры... вдруг кому интересно не смотря в консоль ))
по таймлайну и по консоли время сходится
React.render выполняется например 530ms
после этого еще recalculate style 45ms
а уже после этого Layout 202ms
итого 777ms
202ms - это уже рендер самим браузером 1000 элементов, каждый из которых это 10 простых дивов, спанов и прочее
итого 10К нод
т.е. тут ничего не сделаешь... да?
ну тут я вернусь к своему предложению юзать виртуальный список
т.е. будет пару элементов * 10нод = хх нод - почти мгновенно
тогда как бы должно увеличится время расчета, НО
но и список то тоже будет не весь рендерится
будет ЖЕ выборка именно этих НЕСКОЛЬКИХ элементов списка
как вариант без использования сторонних "виртуальных-листов"
отрисовать первые 10 +- (иль 30 как там у вас)
и по таймауту с минимальной задержкой отрисовать ВСЕ (т.е. первые 30 не обновятся реактом, а останутся в доме не тронутыми)
и еще в качестве дополнения... хотя не знаю как повлиет на отрисовку то
вдруг хоть чутка поможет )) ну хоть сотачку ms бы...
из доки по реакту
Use the production build
If you're benchmarking or seeing performance problems in your React apps, make sure you're testing with the minified production build. The development build includes extra warnings that are helpful when building your apps, but it is slower due to the extra bookkeeping it does.
Да, спасибо, реактом создаем контейнер и получаем его ref, а содержимое наполняем через unstable_renderSubtreeIntoContainer() + заполняем контейнер отрендереными компонентами чистым javascript.
Написано
Войдите на сайт
Чтобы задать вопрос и получить на него квалифицированный ответ.