- PVSM.RU - https://www.pvsm.ru -
Что ж оно так лагает-то?
Если при рендеринге огромной таблицы с какой-нибудь transition анимацией не делать ничего дополнительно, то приложение будет лагать, а пользователь страдать.
В большинстве случаев когда мы используем event listener для создания таблицы с бесконечной прокруткой, нам не только нужно выполнить вычисления, связанные с вьюпортом и высотой строки, но и написать много логики в обработчике прокрутки, чтобы предотвратить слишком частую перерисовку, так как каждый коллбэк скролла будет вызывать setState
.
componentDidMount() {
window.addEventListener('scroll', this.handleScroll)
}
handleScroll(e) {
// use window offset and boundingRect
const { ...someAttributes } = window;
const { ...someBoundingRect } = this.component
// some logic prevent re-render
if ( ... ) return;
// do some math
const newIndex = ...
// and how many rows should be rendered
this.setState({index: newIndex })
}
Но есть и другой подход к реализации бесконечной прокрутки таблицы, без знания чего-либо о значениях window или boundingRect.
Это IntersectionObserver [1]. Определение из w3c [2]:
Эта спецификация описывает API, который можно использовать, чтобы узнать видимость и положение элементов DOM («targets») относительно содержащехся в них элементов
При использовании этого метода вам не нужно знать высоту строки, вершину вьюпорта или вообще любое другое значение для выполнения математики.
Концепция в том, чтобы расставить анкоры с индексами в каждой контрольной точке и каждый раз, когда якорь триггерится, получать значение индекса и перерисовывать таблицу. Благодаря этому не нужно делать какой-нибудь математической магии с высотой DOM и вьюпортом.
Триггер анкора для индекса 1
Рендерим больше строк
Код с IntersectionObserver
будет примерно таким.
handleSentinel = (c) => {
if(!this.observer) {
// создаём observer
this.observer = new IntersectionObserver(
entries => {
entries.forEach(e => {
// если анкор стригерен, рендерим следующую секцию
if (e.isIntersecting) {
this.setState(
{ cursor: +e.target.getAttribute('index') }
);
}
});
},
{
root: document.querySelector('App'),
rootMargin: '-30px',
}
}
if (!c) return;
// наблюдаем за анкором
this.observer.observe(c)
}
render() {
const blockNum = 5;
return(
...
<tbody>
{MOCK_DATA.slice(0, (cursor+1) * blockNum).map(d =>
<Block>
{
// добавляем анкор в каждую контрольную точку
// например, через каждые 5 строк
d.id % blockNum === 0 ?
<span ref={this.handleSentinel} index={d.id / blockNum} />
: null
}
</Block>)}
</tbody>
...
)
}
Автор: germn
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/320838
Ссылки в тексте:
[1] IntersectionObserver: https://developers.google.com/web/updates/2016/04/intersectionobserver
[2] w3c: https://w3c.github.io/IntersectionObserver/
[3] Источник: https://habr.com/ru/post/456046/?utm_campaign=456046&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.