Création d'une table de défilement infinie sans écouteur d'événements

Pourquoi est-il en retard?



Si lors du rendu d'une immense table avec une sorte d'animation de transition, rien d'autre n'est fait, l'application sera en retard et l'utilisateur en souffrira.




Dans la plupart des cas, lorsque nous utilisons l'écouteur d'événements pour créer une table avec un défilement infini, nous devons non seulement effectuer des calculs liés à la hauteur de la fenêtre et de la ligne, mais également écrire beaucoup de logique dans le gestionnaire de défilement pour éviter de redessiner trop souvent, car chaque défilement de rappel sera appelez setState .


Le code serait quelque chose comme ceci:


 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 }) } 

Mais il existe une autre approche pour implémenter le défilement infini d'une table, sans rien savoir des valeurs window ou boundingRect.


Il s'agit d'un IntersectionObserver . Définition du w3c :


Cette spécification décrit une API qui peut être utilisée pour connaître la visibilité et la position des éléments DOM («cibles») par rapport aux éléments qu'ils contiennent.

Lorsque vous utilisez cette méthode, vous n'avez pas besoin de connaître la hauteur de la ligne, le haut de la fenêtre ou toute autre valeur pour faire le calcul.



Le concept consiste à organiser les ancres avec des indices à chaque point de contrôle et chaque fois que l'ancre est déclenchée, obtenir la valeur d'index et redessiner la table. Grâce à cela, vous n'avez pas besoin de faire de magie mathématique avec une hauteur et une fenêtre DOM.



Déclencheur d'ancre pour l'index 1


Rendre plus de lignes


Le code avec IntersectionObserver sera quelque chose comme ça.



 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> ... ) } 

Source: https://habr.com/ru/post/fr456046/


All Articles