Il s'agit d'un mélange d'une table infinie et d'un scénario de défilement infini. La meilleure abstraction que j'ai trouvée pour cela est la suivante:
Aperçu
Créez un <List>
composant qui prend un tableau de tous les enfants. Puisque nous ne les rendons pas, il est vraiment bon marché de simplement les allouer et de les supprimer. Si les allocations de 10k sont trop importantes, vous pouvez à la place passer une fonction qui prend une plage et renvoie les éléments.
<List>
{thousandelements.map(function() { return <Element /> })}
</List>
Votre List
composant garde une trace de la position de défilement et ne rend que les enfants qui sont en vue. Il ajoute un grand div vide au début pour simuler les éléments précédents qui ne sont pas rendus.
Maintenant, la partie intéressante est qu'une fois qu'un Element
composant est rendu, vous mesurez sa hauteur et le stockez dans votre fichier List
. Cela vous permet de calculer la hauteur de l'espaceur et de savoir combien d'éléments doivent être affichés dans la vue.
Image
Vous dites que lorsque l'image se charge, tout "saute" vers le bas. La solution pour cela est de définir les dimensions de l' image dans votre balise img: <img src="..." width="100" height="58" />
. De cette façon, le navigateur n'a pas besoin d'attendre pour le télécharger avant de savoir quelle taille il va être affiché. Cela nécessite une infrastructure mais cela en vaut vraiment la peine.
Si vous ne pouvez pas connaître la taille à l'avance, ajoutez des onload
écouteurs à votre image et, lorsqu'elle est chargée, mesurez sa dimension affichée et mettez à jour la hauteur de ligne stockée et compensez la position de défilement.
Sauter sur un élément aléatoire
Si vous devez sauter sur un élément aléatoire de la liste, cela nécessitera une astuce avec la position de défilement car vous ne connaissez pas la taille des éléments entre les deux. Ce que je vous suggère de faire est de faire la moyenne des hauteurs d'élément que vous avez déjà calculées et de passer à la position de défilement de la dernière hauteur connue + (nombre d'éléments * moyenne).
Comme ce n'est pas exact, cela causera des problèmes lorsque vous reviendrez à la dernière bonne position connue. Lorsqu'un conflit survient, changez simplement la position du défilement pour le résoudre. Cela va déplacer un peu la barre de défilement mais ne devrait pas trop l'affecter.
Spécificités de React
Vous souhaitez fournir une clé à tous les éléments rendus afin qu'ils soient conservés dans tous les rendus. Il existe deux stratégies: (1) avoir seulement n touches (0, 1, 2, ... n) où n est le nombre maximum d'éléments que vous pouvez afficher et utiliser leur position modulo n. (2) avoir une clé différente par élément. Si tous les éléments partagent une structure similaire, il est bon d'utiliser (1) pour réutiliser leurs nœuds DOM. Si ce n'est pas le cas, utilisez (2).
Je n'aurais que deux éléments d'état React: l'index du premier élément et le nombre d'éléments affichés. La position de défilement actuelle et la hauteur de tous les éléments seraient directement associées this
. Lors de l'utilisation, setState
vous effectuez un rendu qui ne devrait se produire que lorsque la plage change.
Voici un exemple de liste infinie utilisant certaines des techniques que je décris dans cette réponse. Ça va être du travail mais React est définitivement un bon moyen d'implémenter une liste infinie :)
jetez un œil à http://adazzle.github.io/react-data-grid/index.html# Cela ressemble à une grille de données puissante et performante avec des fonctionnalités de type Excel et un chargement paresseux / rendu optimisé (pour des millions de lignes) avec fonctionnalités d'édition riches (sous licence MIT). Pas encore essayé dans notre projet mais le fera très bientôt.
Une excellente ressource pour rechercher des choses comme celles-ci est également http://react.rocks/ Dans ce cas, une recherche de balises est utile: http://react.rocks/tag/InfiniteScroll
la source
J'étais confronté à un défi similaire pour modéliser le défilement infini unidirectionnel avec des hauteurs d'éléments hétérogènes et j'ai donc créé un package npm à partir de ma solution:
https://www.npmjs.com/package/react-variable-height-infinite-scroller
et une démo: http://tnrich.github.io/react-variable-height-infinite-scroller/
Vous pouvez consulter le code source pour la logique, mais j'ai essentiellement suivi la recette @Vjeux décrite dans la réponse ci-dessus. Je n'ai pas encore abordé le passage à un élément particulier, mais j'espère le mettre en œuvre bientôt.
Voici les détails de ce à quoi le code ressemble actuellement:
la source