React-window: Prise en charge du contenu mesuré juste à temps

Créé le 30 mai 2018  ·  132Commentaires  ·  Source: bvaughn/react-window

Afin d'éviter d'ajouter des coûts aux composants de liste et de grille existants, créez une nouvelle variante (par exemple DynamicSizeList et DynamicSizeGrid ). Cette variante doit mesurer automatiquement son contenu pendant la phase de validation.

MVP

L'implémentation initiale de ceci pourrait fonctionner de la même manière que le fonctionnement de CellMeasurer dans react-virtualized:

  1. Le contenu n'est mesuré que si aucune mesure de courant n'existe.
  2. Les mesures doivent être réinitialisées en externe (impérativement) si quelque chose change.
  3. Les cellules à un index donné ne peuvent être positionnées qu'après que toutes les cellules avant que cet index ait été mesuré.

But

Ce composant pourrait mieux fonctionner si nous supprimions la troisième contrainte ci-dessus, autorisant un accès aléatoire (par index d'élément ou par décalage de défilement) sans mesurer les éléments précédents. Cela rendrait react-window beaucoup plus performant pour des cas d'utilisation tels que les applications de chat.

Cela débloquerait également la possibilité d'utiliser un ResizeObserver (via -measure ) pour détecter automatiquement le dimensionnement des éléments et supprimer complètement le cache de position et de mesures. Cela supprimerait le besoin de réinitialiser impérativement les mesures mises en cache et améliorerait considérablement l'API.

Pour que ce qui précède soit possible, les composants de liste / grille dynamiques devraient utiliser une approche radicalement différente pour mapper le décalage à l'index et vice versa. ( Ce commentaire sur "l'ancrage du défilement" dans react-virtualized a quelques bons visuels.) Essentiellement, nous aurions besoin de faire quelque chose comme ceci:

  • Estimez la taille totale en fonction du nombre d'articles multiplié par un accessoire estimatedItemSize . (Cette taille estimée n'a pas besoin d'être ajustée, car le mappage décrit ci-dessous n'est pas flou.)

  • Lorsque la position de défilement change, comparez le nouveau décalage au décalage précédent. Si le delta est supérieur à un certain seuil [à déterminer] , définissez le nouveau décalage comme «ancre de défilement». Mappez le décalage à un index estimé (par exemple, divisez le décalage par la taille totale de défilement estimée et multipliez-le par le nombre d'éléments de la collection). Stockez cet index mappé comme «index d'ancrage». Par exemple, si la liste décrite par l'image ci-dessous contenait 250 éléments, «l'indice d'ancrage» serait de 132.

screen shot 2018-06-10 at 11 58 38 am

  • Lorsque la position de défilement change, si le delta est inférieur au seuil , choisissez les nouveaux éléments à rendre par rapport à l'index d'ancrage. Positionnez ces éléments par rapport aux éléments précédemment positionnés. En continuant avec l'exemple ci-dessus, si la liste a été défilée d'une petite quantité (200px), alors 200px de lignes supplémentaires devraient être ajoutées sous les éléments précédemment positionnés:

screen shot 2018-06-10 at 12 01 01 pm

L'approche ci-dessus n'a qu'un seul inconvénient majeur: aligner correctement les éléments aux limites de la liste. Si les indices d'éléments sont estimés (comme décrit ci-dessus), ils ne s'aligneront probablement pas exactement avec le début ou la fin de la zone de défilement.

  • La fin pourrait potentiellement être expliquée en ajustant la taille totale estimée à mesure que l'utilisateur se rapproche de la fin (bien que cela puisse rendre le défilement saccadé).
  • Le début de la liste est plus difficile à gérer, car le premier élément doit s'aligner sur le décalage zéro tout en semblant toujours se connecter de manière contiguë avec des éléments d'un décalage supérieur à zéro. Peut-être qu'un autre seuil pourrait être utilisé, une "zone de sécurité", près du début de la liste (par exemple si le décalage de défilement est inférieur à une valeur absolue) qui forcerait la liste à mesurer toutes les cellules jusqu'à ce point afin qu'elles s'alignent correctement. Le coût de cette mesure forcée serait relativement faible, puisqu'il ne s'agirait que d'un petit nombre d'articles.
    screen shot 2018-06-10 at 5 04 42 pm

Le seul cas qui ne serait toujours pas géré correctement avec l'approche ci-dessus serait une ancre de défilement qui est placée à l'extérieur de la "zone de sécurité" mais un défilement actuel qui va à l'intérieur de la zone de sécurité (comme indiqué ci-dessous). Si l'utilisateur fait lentement défiler vers le début de la liste, il peut être difficile d'aligner la première cellule avec zéro sans introduire de scroll janky.
screen shot 2018-06-10 at 5 08 26 pm

👋 help wanted

Commentaire le plus utile

Il n'y a pas de "vous les gars" sur ce projet. Il est entretenu par une seule personne.

Et c'est un peu inconsidéré de laisser des commentaires sur plusieurs problèmes le même jour en se plaignant de la même chose. Par tous les moyens, veuillez simplement utiliser react-virtualized.

Tous les 132 commentaires

J'utilise ceci dans mui-downshift et j'utilise toujours UNSAFE_componentWillReceiveProps , bien que je prévois d'essayer de porter vers react-window dans un proche avenir (une fois que la hauteur du contenu dynamique sera disponible).

est-ce un mécanisme réutilisable dans UITableView dans IOS?

@luoboding Je ne comprends pas votre question. Pourriez-vous élaborer?

@bvaughn désolé, mon ami, mon anglais n'est pas très bon.

j'ai un problème dans mon projet, j'ai des milliers d'options dans l'élément de sélection, il devient très lent et bloqué lors du rechargement de la page, j'ai essayé d'écrire un composant pour l'améliorer, j'étais un développeur IOS, je connais un mécanisme réutilisable dans UITableView dans IOS, si j'ai besoin d'un élément de sélection de hauteur de 500px, je configure la hauteur de l'élément option à 100px, donc j'ai juste besoin de créer (Math.floor (500/100)) le nombre d'élément d'option et la capacité de la file d'attente (file d'attente de la source de données affichée actuelle ), lorsque je fais défiler l'élément sélectionné vers le haut ou vers le bas, il suffit de pousser ou de sauter dans la file d'attente pour le restituer.

Je veux importer une fenêtre de réaction dans mon projet, est-ce que cela fonctionne comme je l'ai mentionné?

Ce que vous décrivez est le fonctionnement de la fenêtre de réaction (et du fenêtrage, ou élimination par occlusion, en général). Ce n'est pas vraiment lié à ce problème. Il s'agit de mesurer juste à temps le contenu fenêtré. Dans votre cas, les objets ont une hauteur fixe - vous pouvez donc utiliser le composant FixedSizeList : https://react-window.now.sh/#/examples/list/fixed -size

C'est bien de voir l'ancrage traité nativement dans react-window.

Au fait désolé si j'ai un peu trop élevé la barre sur les diagrammes… 😅

@bvaughn quand allez-vous publier cette fonctionnalité, je la recherche

J'ai publié la version 1.0.0 sans cette fonctionnalité car j'ai du mal à trouver le temps (et l'énergie) pour terminer cela maintenant. Prévoyez toujours de l'ajouter à l'avenir. Aucune estimation du moment.

On dirait que la "liste de fer" de Polymer utilise une technique similaire à celle que je propose ici: https://github.com/domenic/infinite-list-study-group/blob/master/studies/Polymer-iron-list.md #virtual -list-dimensionnement

cela serait vraiment utile pour nous, pour le moment, il semble que nous devions synchroniser le CSS avec la logique des composants qui duplique le calcul de la hauteur juste pour le transmettre à la liste virtuelle.

@kevinder pouvez-vous partager comment vous

@carlosagsmendes ne sait pas si cela aidera, mais voici ce que je fais lorsque je l'utilise pour afficher l'historique des discussions:

1.) Dans le constructeur, créez une référence pour la liste et pour mon composant ChatHistory :

  constructor(props) {
    super(props);
    this.listRef = createRef();
    this.chatHistoryRef = createRef();
    this.listHeight = 0;
  }

Je passe ensuite les refs au ChatHistory qui est responsable du rendu de la liste

2.) Dans componentDidMount du composant parent, j'utilise le ChatHistory ref pour obtenir la hauteur de l'élément:

componentDidMount() {
    this.listHeight = this.chatHistoryRef.current.offsetHeight;
}

3.) Dans le composant parent, je maintiens un tableau dans son état avec les détails de l'histoire. Lors de l'ajout d'un nouvel élément à ce tableau, je le fais comme ceci:

  // find out how many pixels in height the text is going to use
  const size = getSize({
    text: displayText,
    className: styles.message,
  });

  let { height } = size;
  height += 20; // adds some spacing in pixels between messages
...rest of items needed for the chat history item..add them all to an array and update state

getSize est basé sur https://github.com/schickling/calculate-size mais je l'ai modifié pour prendre en charge l'acceptation d'un nom de classe. Cette classe est la même que celle utilisée comme conteneur pour afficher les messages individuels

Je suis sûr qu'il existe un meilleur moyen d'y parvenir, mais cela semble assez rapide et je n'ai encore rencontré aucun problème

@osdlge :

@bvaughn chose sûre, j'ai extrait les parties pertinentes de mon code sur https://codesandbox.io/s/5z282z7q1l

Merci pour le partage! 😄

J'ai poussé certains travaux en cours vers une approche initiale du contenu mesuré paresseusement dans une branche nommée issue / 6

J'ai également déployé une démo:
https://react-window-next.now.sh/#/examples/list/dynamic -size

Très cool.

J'essaie toujours de comprendre les problèmes généraux liés au défilement infini tout en parcourant la source de la branche issue / 6 et cette discussion. Donc, la question suivante peut ne pas avoir de sens, mais la voici, car j'aimerais vraiment comprendre cela plus loin:

La mention ci-dessus de «Scroll Anchor» est-elle liée à l' ancrage de défilement en tant que technique comme dans l'article lié ou dans la spécification CSS Scroll Anchoring ?

Merci d'avance

C'est un peu lié de manière tangentielle à votre premier lien, mais pas au second. C'est juste un terme que j'ai choisi d'utiliser pour le problème parce qu'il avait du sens pour moi, pas parce qu'il était lié à une autre spécification ou proposition.

J'ai également publié une version préliminaire de react-window à NPM comme "suivant" (par exemple yarn add react-window@next ).

Vous pouvez jouer avec lui en forçant ce bac à sable de code:
https://codesandbox.io/s/5x8vlm0o7n

Je viens de le tester. J'ai essayé 10000 paragraphes et essayé de sauter à la fin. C'était saccadé.
Si j'ai bien compris, il n'aurait dû mesurer que les lignes estimées à la fin et donc il aurait dû sauter instantanément jusqu'à la fin. Est-ce correct?

Le 12 octobre 2018, à 12h53, Brian Vaughn [email protected] a écrit:

J'ai également publié une version préliminaire de react-window sur NPM comme "next" (par exemple, yarn add react-window @ next).

Vous pouvez jouer avec lui en forçant ce bac à sable de code:
https://codesandbox.io/s/5x8vlm0o7n https://codesandbox.io/s/5x8vlm0o7n
-
Vous recevez ceci parce que vous êtes abonné à ce fil de discussion.
Répondez directement à cet e-mail, consultez-le sur GitHub https://github.com/bvaughn/react-window/issues/6#issuecomment-429271555 , ou désactivez le fil https://github.com/notifications/unsubscribe-auth/ AOf2h7RmSEyGmyrEdMY6GgyZFjCKlDDFks5ukGafgaJpZM4UTb3P .

Non, la branche initiale que j'ai poussée n'implémente pas l'algorithme
décrit dans ce numéro. Il adopte une approche plus naïve le nécessite
mesurer le contenu antérieur avant de rendre le contenu ultérieur.

Désolé pour la confusion!

Le vendredi 12 octobre 2018, 18:34 akraines [email protected] a écrit:

Je viens de le tester. J'ai essayé 10000 paragraphes et j'ai essayé de passer au
finir. C'était saccadé.
Si j'ai bien compris, il n'aurait dû mesurer que les lignes estimées
être à la fin et donc il aurait dû sauter instantanément au
finir. Est-ce correct?

Le 12 octobre 2018, à 12h53, Brian Vaughn [email protected] a écrit:

J'ai également publié une version préliminaire de react-window sur NPM en tant que
"suivant" (par exemple, yarn add react-window @ next).

Vous pouvez jouer avec lui en forçant ce bac à sable de code:
https://codesandbox.io/s/5x8vlm0o7n < https://codesandbox.io/s/5x8vlm0o7n

-
Vous recevez ceci parce que vous êtes abonné à ce fil de discussion.
Répondez directement à cet e-mail, affichez-le sur GitHub <
https://github.com/bvaughn/react-window/issues/6#issuecomment-429271555>,
ou couper le fil <
https://github.com/notifications/unsubscribe-auth/AOf2h7RmSEyGmyrEdMY6GgyZFjCKlDDFks5ukGafgaJpZM4UTb3P
.

-
Vous recevez cela parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub
https://github.com/bvaughn/react-window/issues/6#issuecomment-429282228 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AABznR5R1N0ErukleIfvaLQORF_NECgRks5ukHBHgaJpZM4UTb3P
.

Hey,
Je voulais demander s'il y a une estimation pour une sortie officielle?

Mon équipe utilise react-virtualized pour un nouveau projet que nous avons commencé, mais nous avons besoin de la fonctionnalité de défilement vers le haut et de saut vers un index de ligne spécifique (car vous pouvez supposer que nos lignes ont un contenu dynamique, contenant des images et d'autres contenus changeants).

Recommanderiez-vous de migrer vers react-window dans sa version alpha? Ou devrions-nous attendre une sortie officielle?

De plus, s'il y a un moyen pour que je puisse contribuer à la finition de cette fonctionnalité, j'aimerais beaucoup vous aider 😄

Malheureusement, je ne peux pas m'engager sur un calendrier de publication pour le moment car je n'ai pas fait beaucoup de tests et je ne sais pas quels types de problèmes je vais rencontrer lorsque je le ferai (ou combien de temps cela prendra pour résoudre eux).

Si vous souhaitez contribuer, une solution serait de tester la version alpha et de me faire savoir dans quelle mesure elle fonctionne, et si vous trouvez des bogues.

Je vais probablement me concentrer davantage sur cela bientôt, mais je ne peux pas dire dans combien de temps. Surtout pour la semaine ou les deux prochaines, je suis distrait par React conf et par la préparation de la version 16.6.

@bvaughn excellent travail 👏 Enfin un peu de temps pour jouer. 🕹

Il semble que nous ayons besoin de quelques ajustements pour masquer la liste avec display: none Par exemple, vous avez une page avec deux onglets et souhaitez basculer entre eux sans perdre votre état actuel (position de défilement, etc.), à mon avis ce n'est pas un cas d'utilisation rare .

Simple Code Sandbox présentant le problème:
https://codesandbox.io/s/p7vq18wmjq

Cela se produit parce que lorsque nous déclenchons l'affichage aucun, tous les enfants auront offsetHeight === 0
resize observe les kiks et met à jour les nouvelles valeurs. react-window ne devrait pas se soucier de cette situation si l'appelant a décidé de le cacher, basic devrait le gérer en bloquant handleNewMeasurements

si cette ligne
https://github.com/bvaughn/react-window/blob/issues/6/src/DynamicSizeList.js#L443
changerait en

handleNewMeasurements: instance._handleNewMeasurements

alors nous pouvons remplacer la logique par défaut

let _handleNewMeasurements

<DynamicSizeList  
  ref={current => {
    if (current) {
      _handleNewMeasurements = current._handleNewMeasurements
      current._handleNewMeasurements = (...args) => {
        if (!isHidden) {
          return _handleNewMeasurements(...args)
        }
      }
    }
  }}
  {...otherProps}

J'ai poussé une mise à jour dans cette branche (et publié une nouvelle balise @next à NPM) qui corrige le bogue de défilement lisse de Firefox en utilisant margin-top pour tenir compte des éléments redimensionnés pendant que le défilement est en cours. C'est plus compliqué que je ne le souhaiterais, mais je ne connais pas de meilleure façon de gérer cela pour le moment. (Je dois également faire quelques tests supplémentaires de cette approche, car je pense qu'elle pourrait avoir des aspérités encore dans des cas extrêmes.)

J'apprécie les commentaires ci-dessus, @piecyk. Je n'ai pas encore eu le temps de creuser dedans. (Ce n'est encore qu'une sorte de projet parallèle pour moi pour le moment.)

Il semble que je puisse supprimer le hack de marge en faveur de scrollBy pour Firefox au moins . Il faut d'abord tester IE et Edge. Ils peuvent avoir leurs propres défis.

Ouais @bvaughn je sais, travail génial 👏 Je ne sais pas comment tu trouves le temps! 🥇Kudos à vous!

Mais revenons au problème lorsque la liste est dans un élément DOM qui est caché avec display none, de base, nous devons vérifier si le wrapper a une hauteur, une largeur sinon nous ne voulons pas commencer le rendu (courant, il essaiera de rendre liste entière) Essayera demain de le réparer (ayez quelque chose de caché)

Ouais. Je comprends le cœur du problème que vous décrivez. Je n'aime pas l'idée de pirater autour de lui en surchargeant / monkey-patching plus de méthodes d'instance, alors j'aimerais d'abord y réfléchir davantage.

On dirait que le package @next est cassé?

https://codesandbox.io/s/5x8vlm0o7n

Je ne sais pas si c'est le bon endroit pour laisser une question, alors excusez-moi si je me trompe. Donc, en bref:

  • J'ai utilisé DynamicSizeList avec AutoResizer et en général cela fonctionne très bien. Gloire!
  • On m'a demandé d'introduire des lignes dont le contenu peut se développer (en ajoutant un div supplémentaire avec des informations supplémentaires) et se rétracter.
  • J'ai également ajouté (via redux) un accessoire sur ces lignes qui écoute les actions globales d'expansion / retrait.
  • Les choses amusantes commencent. Je clique sur développer / rétracter et tout a fière allure!
  • Si je fais défiler un peu puis que je développe / rétracte toutes les lignes, le nombre de lignes rétractées est le même que celui des lignes développées. Si je déplie à nouveau, le nombre passe à la moitié et ainsi de suite.
    (c'est-à-dire 30 rangées rétractées -> 10 déployées -> clic rétracté -> 10 rangées rétractées -> clic agrandie -> 3 rangées agrandies -> clic rétractée -> 3 rangées rétractées).

J'ai essayé de recharger le itemData en fournissant un objet différent mais identique avec le hack JSON.parse (JSON.stringify (data)). Pas de chance :-(

Je soupçonne une erreur de calcul de la hauteur. Une idée pour surmonter ce problème?

Pourriez-vous partager un exemple de codesandbox? J'ai besoin de faire quelque chose de similaire pour que nous puissions peut-être nous entraider

@vtripolitakis Je viens de trouver un exemple avec des lignes extensibles . Voici le lien vers la discussion

@carlosagsmendes merci pour cela, mais mon étude de cas est un peu différente car j'utilise le DynamicSizeList :-(

J'ai donc trouvé la raison du problème:
state.scrollOffset prenait des valeurs négatives.

sur src/DynamicSizeList.js nous devons ajouter le code suivant à la ligne 299

if (sizeDeltaForStateUpdate < 0) {
          sizeDeltaForStateUpdate = 0;
        }

Hm ... Je ne m'attendrais pas à ce que cette solution soit correcte, en un coup d'œil. Un delta de taille pourrait légitimement être négatif, non?

Peut-être devrions-nous avoir une garde ( Math.max(0, prevState.scrollOffset + sizeDeltaForStateUpdate) ) autour de l'endroit où la state.scrollOffset est mise à jour?

Bonjour, lorsque j'ai débogué mon cas, sizeDeltaTotal pris des valeurs négatives et a donc rendu sizeDeltaForStateUpdate négatif, ce qui a donné un state.scrollOffset négatif après la mise à jour de l'état.

Cela s'est produit lorsque j'ai développé et retiré des éléments, puis j'ai fait défiler vers le haut avec scrollOffset 0 et la direction backwards . Ensuite, si je dilate et me rétracte plusieurs fois, j'ai les négatifs.
Oui, votre suggestion devrait être tout aussi bonne. ~ Le tester maintenant. ~ Fonctionne correctement.

@marcneander essayez la version 1.4.0-alpha.1

En ce qui concerne l'ignorance des événements de redimensionnement lorsque la liste est masquée, peut-être quelque chose comme ça https://github.com/piecyk/react-window/commit/acfd88822156611cfd38872acdafbbefd2d0f78f
@bvaughn qu'en pensez-vous?

J'essaie d'ajouter le défilement automatique dans une application de style chatbox et je rencontre ce problème: DynamicSizeList does not support scrolling to items that have not yet measured. scrollToItem() was called with index 111 but the last measured item was 110.

J'essaye d'appeler scrollToItem(items.length-1) en componentDidUpdate

Est-ce un comportement intentionnel?

Ouais, peut-être que quelque chose comme ça pourrait fonctionner @piecyk 👍

Est-ce un comportement intentionnel?

Ça ne sonne pas comme ça @xaviergmail , non. Peut-être un bug.

hey @bvaughn Je ne veux pas faire dérailler ce problème, mais je voulais dire qu'il y a une implémentation de des internes Flex 4 DataGrid qui peut être en mesure d'aider ici. Je sais que Flash est: -1:, mais la dernière version de Flex avait en fait un très bon moteur de mise en page virtualisé ... parce que Flash :-)

Le LinearLayoutVector est un tableau clairsemé pour le mappage entre les indices d'éléments et les positions de pixels dans une seule dimension. Les trois opérations de base sont:

interface LinearLayoutVector {
   start: (index) => position;
     end: (index) => position;
  indexOf: (position) => index;
}

En interne, il alloue des seaux en puissances de 2 pour stocker les positions des articles (la puissance spécifique peut être réglée pour mieux s'adapter aux tailles d'articles plus grandes ou plus petites). Cela permet des recherches O (1) index -> position temps constant et une analyse de bloc linéaire efficace pour les recherches position -> index . Il prend en charge le remplissage, les espaces, les tailles par défaut et l'insertion, la suppression et les mises à jour à accès aléatoire.

Je l'ai porté sur JS il y a environ 6 ans lorsque je faisais beaucoup d'interfaces virtualisées pour mobile. Il pourrait utiliser une mise à jour vers ES6 pour plus de lisibilité, et pourrait probablement augmenter la vitesse en passant à des tableaux typés, mais la logique de base est saine.

Il y a quelques semaines, j'ai soumis un projet de PR pour réactiver la virtualisation qui a changé les éléments internes de CellSizeAndPositionManager avec le LLV et cela a résolu quelques problèmes d'invalidation de perf / cache. Si vous êtes en panne, je serais heureux de soumettre un PR similaire à react-window dans les prochaines semaines.

Salut @trxcllnt 👋

Si vous souhaitez partager un PR, je serais heureux de jeter un coup d'œil. Vous voudriez le faire contre la branche issues/6 (WIP PR # 102).

En un coup d'œil, linear-layout-vector ne semble pas avoir subi de tests ou être trop utilisé, donc j'aurais un peu de réticence au départ, mais je serais toujours prêt à y jeter un coup d'œil. Je voudrais également regarder le poids qu'il ajoute à un paquet après avoir été uglifié + minifié, mais je ne m'attendrais pas à ce qu'il en ajoute trop. 😄

@bvaughn pas de

Après avoir commenté, je me suis souvenu que j'avais la démo pour laquelle j'avais fait le port: https://github.com/trxcllnt/virt-list. Accédez à ce site de pages GH et lancez la liste des films à gauche et à droite (cela était lié à certaines discussions sur les performances de rendu que nous avions dans l'équipe iOS de Netflix).

@bvaughn Merci pour tout le travail
Je teste actuellement ^1.6.0-alpha.1 et je prévois une livraison en production avec cette version.

Je pensais que je publierais ce que je devais faire pour travailler avec le nouveau DynamicSizeList pour quiconque examine ce problème et utilise la dernière version de la branche.

Suivre les documents liés ci-dessus et ceux générés à partir de la branche issues / 6 conduira à

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

et donc le correctif était d'imiter ce que vous faites dans les tests et ...

import { DynamicSizeList as List } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';

// in constructor(props) for handling scrolling
this.listRef = React.createRef();

// in render()
const allItems = [...];
const Renderer = ({ forwardedRef, style, index, ...rest }) => (
  <div ref={forwardedRef} style={style}>
    <MyCoolComponent index={index} otherProps={otherPropsBasedOnAllItems} />
  </div>
);

const RefForwarder = React.forwardRef((props, ref) => (
  <Renderer forwardedRef={ref} {...props} />
));

return <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
  <div style={{ flexGrow: 0, flexShrink: 0, width: '100%', position: 'sticky', top: 0, zIndex: zIndexHideLayers }}>
    <MyCoolComponentThatControlsScrolling listRef={this.listRef} />
  </div>
  <div style={{ flex: 1, width: '100%' }}>
    <AutoSizer>
      {({ height, width }) => (
        <List ref={this.listRef} itemCount={allItems.length} width={width} height={height}>
          {RefForwarder}
        </List>
      )}
    </AutoSizer>
  </div>
</div>;

Mon exemple comprend probablement plus que ce que vous voudriez sur cette page de documentation, mais j'espère que cela facilitera la mise à jour de la documentation pour vous

Des commentaires sur la version actuelle de la branche?
💯 fonctionne bien
🎉 merci encore pour tout le travail!

edit: DynamicSizeList rend sérieusement cette bibliothèque si facile à utiliser maintenant.

Merci d'avoir partagé les détails! Quand j'aurai de la bande passante pour récupérer ce problème, je vais les explorer.

Je pense que cette approche peut être utilisable avec la proposition originale dans ce numéro.

Plutôt que d'utiliser la taille précédente de l'article, nous pourrions simplement utiliser les tailles estimées et affiner avec les tailles réelles au fur et à mesure que quelqu'un fait défiler. (Je ne pense pas qu'il y ait une distinction importante entre "taille précédemment mesurée" et "taille estimée", à l'exception du fait que la taille précédemment mesurée est susceptible d'être plus précise. Néanmoins, cela pourrait être un compromis acceptable car cela permettrait nous pour sauter à des endroits arbitraires dans les données sans rendre les choses qui précèdent, _et_ cela nous libérerait d'avoir à maintenir un cache de taille d'élément.)

Je pense que cela pourrait simplifier considérablement le problème d'ancrage du scroll. Nous pourrions simplement faire le saut initial (comme décrit) et ensuite faire comme si tout "avant" (ci-dessus ou à gauche) était exactement la taille estimée. Puis au fur et à mesure que nous faisons défiler, affinez.

Pourrait peut-être fonctionner?

@bvaughn Est-ce que cela résoudra le problème que

https://codesandbox.io/s/vr648ywy3

Gardons les commentaires sur ce problème axés sur la discussion de l'API, pas sur le dépannage.

Je suggère Stack Overflow pour poser des questions.

Est-il possible d'exposer le resetAfterIndex dans cette API? J'ajoute, modifie et supprime de ma DynamicSizeList et, au moins d'après ce que je peux rassembler, ce serait la méthode à appeler pour corriger les hauteurs, oui?

@bvaughn a joué pendant le week-end avec l'idée de positionner les éléments avec un index d'ancrage et de faire défiler la liste pour aligner ce que l'utilisateur voit ... Premières impressions que cela pourrait fonctionner 😅 Pour plus de simplicité, la liste est rendue sans aucun élément de surbalayage, aussi nous besoin de changer le fonctionnement du cache (dans ce wip, il est toujours effacé) ... Que pensez-vous?

implémentation poc https://github.com/piecyk/react-window/pull/2/files
voici le sandbox de code exécutant la construction de la branche
https://codesandbox.io/s/4x1q1n6nn9

uh-oh, Firefox ne peut pas suivre le rendu lors du défilement rapide comme le fait Chrome en utilisant cette approche 🤷‍♂️

J'essaie d'ajouter le défilement automatique dans une application de style chatbox et je rencontre ce problème: DynamicSizeList does not support scrolling to items that have not yet measured. scrollToItem() was called with index 111 but the last measured item was 110.

J'essaye d'appeler scrollToItem(items.length-1) en componentDidUpdate

Est-ce un comportement intentionnel?

Un peu tard mais j'essaie de résoudre ce problème avec ce crochet de réaction.

Ce n'est pas la meilleure solution mais j'y travaille toujours. Peut-être pouvons-nous travailler pour le rendre plus générique (et simple) et créer un package?

Gif pour montrer comment cela fonctionne actuellement:
https://cl.ly/87ca5ac94deb

Peut-être pouvons-nous ouvrir un nouveau problème pour parler d'une solution à ce comportement de type chat?

uh-oh, Firefox ne peut pas suivre le rendu lors du défilement rapide comme le fait Chrome en utilisant cette approche

On dirait que cela fonctionne dans la version 68 de Firefox Nightly.

@bvaughn J'utilise DynamicSizeList avec les composants InfiniteLoader et Autosizer pour essayer de créer un flux. J'aime ce que je suis seeng jusqu'à présent, continuez comme ça :)

En termes d'API et de comportement:

  1. Pouvons-nous obtenir l'objet de données comme deuxième argument dans le rappel itemKey, tel qu'il est dans FixedSizeList?

  2. Pouvons-nous réinitialiser la hauteur du conteneur interne lorsque l'objet de données est filtré / modifié.

J'utilise depuis un moment DynamicSizeList de 1.6.0-alpha.1 avec InfiniteLoader et cela fonctionne très bien. Merci pour la fonctionnalité géniale!

Cependant, je dois maintenant utiliser scrollToItem() . Similaire à un commentaire ci-dessus, mais distinct car rien du tout n'est encore mesuré, j'obtiens:

DynamicSizeList does not support scrolling to items that yave not yet measured. scrollToItem() was called with index 9 but the last measured item was -1.

Cela ne semble pas être lié au timing car j'ai essayé de l'appeler après un long setTimeout . Alors, puis-je forcer une mesure? Ou existe-t-il des solutions de contournement?

EDIT : Nevermind, initialScrollOffset fait ce dont j'avais besoin.

pourquoi utiliser findDOMNode?

Existe-t-il des définitions de type pour la branche @next ?

@WillSquire non, ils ne le font pas. Je ne sais pas non plus s'il est possible de les publier à la balise @next dans DefinitelyTyped (je me trompe peut-être). De plus, je pense qu'il serait préférable d'attendre que cette branche soit finalement fusionnée et qu'une nouvelle version soit publiée, car l'API pourrait encore changer.

@bvaughn J'étais prêt à l'utiliser chez devhub , mais avant d'investir dans son intégration, pensez-vous qu'il est déjà en bon état ou qu'il a encore des problèmes de blocage?

@brunolemos Ma liste de

tiens moi au courant!

~ J'ai essayé de l'utiliser mais je n'ai pas réussi jusqu'à présent. ~

Ça marche mais les performances ne sont pas bonnes. Peut-être que mes rendus d'articles sont chers ou autre chose.

https://github.com/devhubapp/devhub/pull/152

Il semble que quelque chose se soit cassé dans la dernière version lors de l'utilisation d'AutoSizer avec une hauteur de conteneur de 100%

Edit: j'ai pu trouver une solution de contournement en utilisant 100vh et calc ()

quelque chose s'est peut-être cassé

Trop vague pour être exploitable. Partager une repro avec le comportement attendu?

J'utilise DynamicSizeList de 1.6.0-alpha.1 avec différents filtres et une vue de carte complexe. Mais nous devons envelopper avec la hauteur et la largeur. Cela fonctionne très bien pour moi.

Merci les gars

Bonjour, j'essaye DynamicSizeList , mais tous mes éléments sont rendus les uns sur les autres. Je passe l'attribut de style à l'élément rendu, mais si je consigne style , je vois que height n'est pas défini pour chaque élément, top et left sont toujours 0 .
Qu'est-ce que j'ai manqué ici :-)?

@ graphee-gabriel vous manquez un exemple de reproduction.

La hauteur n'est pas spécifiée intentionnellement au départ, afin de laisser les éléments s'afficher avec leur taille naturelle ...

Ok, je comprends la logique, alors ce n'est pas la raison pour laquelle les éléments sont affichés les uns sur les autres.
Je vais fournir autant de données que possible, j'ai pensé que j'ai peut-être fait une erreur commune ou raté une étape évidente qui conduit à ce problème (comme ne pas transmettre l'objet de style).

Screen Shot 2019-07-07 at 18 08 53

import React from 'react'
import { DynamicSizeList as List } from 'react-window'

import Layout from '../Layout'
import Text from '../Text'
import withScreenDimensions from '../withScreenDimensions'

class ListView extends React.Component {
  state = {
    availableHeight: 0
  }

  componentDidMount() {
    const checkForHeightChange = () => {
      if (this.containerDiv) {
        const { offsetHeight } = this.containerDiv
        if (this.offsetHeight !== offsetHeight) {
          this.offsetHeight = offsetHeight
          this.setState({ availableHeight: offsetHeight })
        }
      }
    }
    checkForHeightChange()
    this.intervalId = setInterval(checkForHeightChange, 10)
  }

  componentWillUnmount() {
    clearInterval(this.intervalId)
  }

  render() {
    const {
      data,
      renderItem,
      emptyText,
      dimensions,
    } = this.props
    const { width } = dimensions
    const { availableHeight } = this.state
    return (
      <Layout
        centerVertical
        style={{
          height: '100%',
        }}>
        {data && data.length > 0 ? (
          <div
            style={{
              display: 'flex',
              flex: 1,
              height: '100%',
              backgroundColor: 'red',
              alignItems: 'stretch',
              justifyContent: 'stretch',
            }}
            ref={ref => this.containerDiv = ref}
          >
            <List
              height={availableHeight}
              itemCount={data.length}
              width={width > 800 ? 800 : width}
            >
              {({ index, style }) => {
                console.log('style', style)
                return (
                  <div style={style}>
                    {renderItem({
                      item: data[index], index
                    })}
                  </div>
                )
              }}
            </List>
          </div>
        ) : (
            <Text bold center padding accent>{emptyText}</Text>
          )}
      </Layout>
    )
  }
}


export default withScreenDimensions(ListView)

Partager un bac à sable de code où je peux voir cela?

Je suggérerais _pas_ d'utiliser une fonction en ligne pour votre rendu d'élément car cela provoque des remontages inutiles en raison du fait qu'il change à chaque fois que le parent est rendu. (C'est pourquoi tous les exemples évitent les fonctions en ligne.)

@ graphee-gabriel J'ai eu ceci aussi, la documentation ne le mentionne pas mais vous devez faire en sorte que votre composant de ligne supporte la réception d'une référence:

Row = React.forwardRef(
      (row, ref) => (
        <div ref={ref} style={row.style}>
          {renderItem({
            item: data[row.index],
            index: row.index,
          })}
        </div>
      ),
    )

Bonjour, c'est parti:

https://codesandbox.io/s/sweet-sea-irxl8?fontsize=14

Oui en effet pour les fonctions en ligne, c'est un très vieux code que j'ai essayé de migrer vers react-window, et je n'ai pas pris le temps de l'améliorer ici aussi.
Merci pour vos commentaires. Faites-moi savoir ce que vous trouvez dans ce bac à sable.

Annnnnd J'aurais dû vérifier le message @brunolemos avant de faire ce sandbox hehe.
C'était l'étape manquante et j'ai résolu mon problème, merci!

Cela a soulevé un autre problème, j'ai mis à jour le bac à sable pour que vous puissiez reproduire @bvaughn
Trouvez-le ici: https://codesandbox.io/s/sweet-sea-irxl8

Maintenant, la liste fonctionne bien, mais étrangement, elle semble augmenter avec le contenu et ne rétrécit plus jamais.

Sens:

  1. Si je montre 6 éléments, faites défiler jusqu'à la fin, tout va bien.
  2. Changez le contenu pour afficher 20 éléments, faites défiler jusqu'à la fin, tout va bien.
  3. Remettez le contenu à 6 éléments, faites défiler jusqu'au dernier élément, mais je peux continuer à faire défiler sur un espace blanc qui semble être laissé du contenu précédent (l'ensemble de données de 20 éléments).

Cela a soulevé un autre problème, j'ai mis à jour le bac à sable pour que vous puissiez reproduire @bvaughn
Trouvez-le ici: https://codesandbox.io/s/sweet-sea-irxl8

Maintenant, la liste fonctionne bien, mais étrangement, elle semble augmenter avec le contenu et ne rétrécit plus jamais.

Sens:

  1. Si je montre 6 éléments, faites défiler jusqu'à la fin, tout va bien.
  2. Changez le contenu pour afficher 20 éléments, faites défiler jusqu'à la fin, tout va bien.
  3. Remettez le contenu à 6 éléments, faites défiler jusqu'au dernier élément, mais je peux continuer à faire défiler sur un espace blanc qui semble être laissé du contenu précédent (l'ensemble de données de 20 éléments).

J'ai le même problème

C'est exactement ce dont j'avais besoin.
Je viens de tester la DynamicSizeList de 1.6.0-alpha.1 en combinaison avec react-virtualized-auto-sizer et react-window-infinite-loader avec de très bons résultats.
Est-ce que je peux vous aider à faire avancer les choses?

Bonjour @bvaughn , avez-vous eu le temps de vérifier les codesandbox de https://github.com/bvaughn/react-window/issues/6#issuecomment -509213284?

Bonjour, j'utilise DynamicSizeList pour mon application de chat.
Merci pour la fonctionnalité géniale.

Cependant, j'ai des problèmes avec de mauvaises performances et beaucoup de traitement de script.
Lors du défilement, le CPU augmente toujours et atteint souvent 100%.
Avez-vous des idées de solutions?

import { useChatList } from '../../../hooks/chat/useChatList';
import LoadingSpinner from '../../../utils/LoadingSpinner';

import dynamic from 'next/dynamic';
import * as React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
// @ts-ignore
import { DynamicSizeList as List } from 'react-window';
import { Message } from 'src/app/typings';

const { useRef, useCallback } = React;

const RowItem = React.memo(
  ({ forwardedRef, style, index, data }: any) => {
    const item = data[index] as Message;
    if (item) {
      return (
        <div id={item.messageId} ref={forwardedRef} style={style}>
          {item.text && item.text.plainText}
        </div>
      );
    }
    return null;
  },
  (prevProps, newProps) => {
    const { index, data } = prevProps;
    const { index: newIndex, data: newData } = newProps;
    let isMemo = true;
    isMemo = isMemo && index === newIndex;
    isMemo = isMemo && data.length === newData.length;
    return isMemo;
  }
);

function ChatList() {
  const listRef = useRef<HTMLInputElement>();

  const { formatMessages: messages, isLoadingMessages } = useChatList();

  const keyCreator = useCallback((index: number) => `ChatList/RowItem/${messages[index].messageId}`, [messages]);

  if (isLoadingMessages && (!messages || messages.length <= 0)) {
    return <LoadingSpinner />;
  }
  return (
    <div style={{ flex: 1, height: '100%', width: '100%' }}>
      <AutoSizer>
        {({ height, width }) => (
          <List
            ref={(lref: HTMLInputElement) => {
              if (lref !== null) {
                listRef.current = lref;
              }
            }}
            itemCount={messages.length}
            itemData={messages}
            itemKey={keyCreator}
            height={height}
            width={width}
            overscanCount={10}
          >
            {React.forwardRef((props, ref) => (
              <RowItem forwardedRef={ref} {...props} />
            ))}
          </List>
        )}
      </AutoSizer>
    </div>
  );
}

export default ChatList;

スクリーンショット 2019-07-14 11 49 54

Bonjour @bvaughn , beau travail!
Quelle est la bonne façon de recalculer la hauteur des éléments lors du redimensionnement du lieu de travail? Avec l'aide des commentaires ci-dessus, je fais une démo https://codesandbox.io/s/angry-hill-tcy2m
Lorsque la largeur du lieu de travail change à la souris, j'ai besoin de recalculer la hauteur de tous les éléments (et peut-être effacer le cache de hauteur interne du composant VariableSizeList) ...

y a-t-il une solution maintenant pour la liste dynamique je viens de passer 4 heures à essayer de la faire fonctionner hein
après avoir lu tous les commentaires, j'ai terminé 😠
Si vous avez une solution de travail, veuillez me fournir

Il n'y a pas de "vous les gars" sur ce projet. Il est entretenu par une seule personne.

Et c'est un peu inconsidéré de laisser des commentaires sur plusieurs problèmes le même jour en se plaignant de la même chose. Par tous les moyens, veuillez simplement utiliser react-virtualized.

Je suis vraiment désolé d'avoir laissé un commentaire comme celui-ci. J'ai trouvé ce problème plus tard, puis j'ai lu tous les commentaires et j'ai pensé que d'autres vous aidaient au moins

@ShivamJoker J'ai presque réussi à le faire fonctionner, la seule chose qui reste pour qu'il fonctionne parfaitement est la hauteur totale qui ne cesse de croître mais ne diminue jamais après avoir changé le contenu en moins d'éléments. Si cela est résolu, dans mon cas d'utilisation, cela semble fonctionner parfaitement.

@bvaughn auriez-vous le temps de vérifier l'exemple dans le bac à sable de https://github.com/bvaughn/react-window/issues/6#issuecomment -509213284?

=> https://codesandbox.io/s/sweet-sea-irxl8

Cela commence par la liste plus courte, donc:

  • faites défiler jusqu'à la fin de la liste
  • faites défiler vers le haut et cliquez sur Show Long List
  • faites défiler jusqu'à la fin
  • faites défiler vers le haut et cliquez sur Show Short List
  • Enfin, faites défiler une dernière fois vers le bas pour voir que la liste courte est maintenant suivie de nombreux espaces vides.

Merci!

@ShivamJoker J'ai presque réussi à le faire fonctionner, la seule chose qui reste pour qu'il fonctionne parfaitement est la hauteur totale qui ne cesse de croître mais ne diminue jamais après avoir changé le contenu en moins d'éléments. Si cela est résolu, dans mon cas d'utilisation, cela semble fonctionner parfaitement.

@bvaughn auriez-vous le temps de vérifier l'exemple dans le bac à sable du n ° 6 (commentaire) ?

=> https://codesandbox.io/s/sweet-sea-irxl8

Cela commence par la liste plus courte, donc:

  • faites défiler jusqu'à la fin de la liste
  • faites défiler vers le haut et cliquez sur Show Long List
  • faites défiler jusqu'à la fin
  • faites défiler vers le haut et cliquez sur Show Short List
  • Enfin, faites défiler une dernière fois vers le bas pour voir que la liste courte est maintenant suivie de nombreux espaces vides.

Merci!

Ouais, fondamentalement, le conteneur interne devrait réinitialiser sa hauteur lors du filtrage / changement des données.

@ShivamJoker J'ai presque réussi à le faire fonctionner, la seule chose qui reste pour qu'il fonctionne parfaitement est la hauteur totale qui ne cesse de croître mais ne diminue jamais après avoir changé le contenu en moins d'éléments. Si cela est résolu, dans mon cas d'utilisation, cela semble fonctionner parfaitement.

@bvaughn auriez-vous le temps de vérifier l'exemple dans le bac à sable du n ° 6 (commentaire) ?

=> https://codesandbox.io/s/sweet-sea-irxl8

Cela commence par la liste plus courte, donc:

  • faites défiler jusqu'à la fin de la liste
  • faites défiler vers le haut et cliquez sur Show Long List
  • faites défiler jusqu'à la fin
  • faites défiler vers le haut et cliquez sur Show Short List
  • Enfin, faites défiler une dernière fois vers le bas pour voir que la liste courte est maintenant suivie de nombreux espaces vides.

Merci!

merci d'avoir mis en œuvre le même en espérant que cela fonctionnera bien pour les autres utilisateurs
et oui j'ai aussi vu que le problème de hauteur avec le scroll

@ graphee-gabriel mais j'ai aussi un autre problème que ma barre d'applications utilisait pour se cacher lors du défilement vers le bas, ce qui ne se produit pas maintenant quelle peut être la solution?
image

Bonne journée. J'ai utilisé DinamycSizeList dans mon projet de démonstration. Tout allait bien, mais au bout d'un moment, j'ai remarqué que le composant de liste commençait à ne pas fonctionner correctement. Au début, je pensais que c'était une bibliothèque dont dépendait la fenêtre de réaction. Mais en regardant ta démo
https://react-window-next.now.sh/#/examples/list/dynamic -size
remarqué à peu près le même résultat, même si dans le passé cela a également fonctionné parfaitement. Pouvez-vous suggérer la cause de ces bugs?

@simeonoff

Ouais, fondamentalement, le conteneur interne devrait réinitialiser sa hauteur lors du filtrage / changement des données.

comment dois-je faire j'ai essayé de mettre une hauteur d'état mais cela ne semble pas fonctionner
Toute solution ?

@simeonoff

Ouais, fondamentalement, le conteneur interne devrait réinitialiser sa hauteur lors du filtrage / changement des données.

comment dois-je faire j'ai essayé de mettre une hauteur d'état mais cela ne semble pas fonctionner
Toute solution ?

Il doit être implémenté en interne par la bibliothèque.

@ShivamJoker J'ai presque réussi à le faire fonctionner, la seule chose qui reste pour qu'il fonctionne parfaitement est la hauteur totale qui ne cesse de croître mais ne diminue jamais après avoir changé le contenu en moins d'éléments. Si cela est résolu, dans mon cas d'utilisation, cela semble fonctionner parfaitement.

@bvaughn auriez-vous le temps de vérifier l'exemple dans le bac à sable du n ° 6 (commentaire) ?

=> https://codesandbox.io/s/sweet-sea-irxl8

Cela commence par la liste plus courte, donc:

  • faites défiler jusqu'à la fin de la liste
  • faites défiler vers le haut et cliquez sur Show Long List
  • faites défiler jusqu'à la fin
  • faites défiler vers le haut et cliquez sur Show Short List
  • Enfin, faites défiler une dernière fois vers le bas pour voir que la liste courte est maintenant suivie de nombreux espaces vides.

Merci!

Vous pouvez définir la clé pour éviter les espaces vides.
https://codesandbox.io/s/blissful-voice-mzjsc

Bonjour @bvaughn merci pour ce super projet!

Par nécessité, j'ai passé un certain temps dans le code DynamicLists à essayer de comprendre comment faire défiler n'importe où sans aucune limitation et comment faire défiler jusqu'à n'importe quel élément, mesuré et non.

J'ai réussi à le faire ici https://github.com/bvaughn/react-window/compare/issues/6...Sauco82 : issues / 6 en supprimant lastMeasuredIndex et en vérifiant par article à la place avec itemIsMeasured , ce qui nécessite évidemment de nombreux autres changements.

Je n'ai jamais participé à un projet open source ni utilisé Flow, donc je ne sais pas si cela est utile ou vaut la peine d'être inclus, ni si je devrais directement essayer un PR ou en discuter ici.

Je suis heureux d'aider et de peaufiner, donc si vous avez besoin de quelque chose, faites-le moi savoir.

Hé, voici une solution beaucoup plus simple (pas besoin d'ajouter des éléments fantômes au DOM pour calculer leur taille):
Codesandbox

Hé, voici une solution beaucoup plus simple (pas besoin d'ajouter des éléments fantômes au DOM pour calculer leur taille):
Codesandbox

Impressionnant! Ça marche pour moi. Bon travail.

@Kashkovsky a calculé la taille si la mise à jour était
et itemSize appel une fois

@ userbq201 @Kashkovsky excellente solution de contournement! D'une manière ou d'une autre, dans mon cas, cela n'a pas fonctionné dès la sortie de la boîte, j'ai dû modifier le code de ChatHistory.js comme suit:

    const listRef = useRef(); // added
    const sizeMap = useRef({});
    const setSize = useCallback((index, size) => {
        sizeMap.current = {...sizeMap.current, [index]: size};
        listRef.current.resetAfterIndex(index); // added
    }, []);
    const getSize = useCallback(index => sizeMap.current[index] || 60, []);
    // ...
    <List ref={listRef}

Sinon, tous les éléments sont rendus avec la même hauteur par défaut. Dans votre cas, cela fonctionne tel quel, je ne peux pas expliquer pourquoi il y a une différence ... peut-être que @bvaughn le peut.

@bvaughn et si nous devions activer un comportement similaire pour SSR? un indice pour ce côté?

@bvaughn C'est moi ou votre démo ne fonctionne pas?

Belle implémentation @Kashkovsky @ kirill-konshin et @ userbq201 !

Comment aborderiez-vous l'utilisation de la mémorisation avec cette solution?

J'ai essayé d'encapsuler ChatMessage dans un memo avec areEqual , mais React restitue toujours chaque objet chaque fois qu'un message est ajouté à la liste.

Dans mes autres FixedSizedLists, la mémorisation fonctionne bien avec ce wrapper memo / areEqual, mais peut-être que ref={root} affecte?

Vous pouvez facilement dire si React re-rend les composants en collant un

J'ai bifurqué l'exemple ici: https://codesandbox.io/s/dynamic-size-of-react-window-list-items-nb038


EDIT: J'ai corrigé la mémorisation - elle est destinée à envelopper le composant fonctionnel initial avec un mémo - pas le comme je l'avais fait. Voici une solution mémorisée au cas où quelqu'un aurait une structure DOM complexe dans ses listes (ou s'il doit cartographier des vidéos comme moi): https://codesandbox.io/s/dynamic-size-of-react-window-list -items-errt4


EDIT 2: Il s'avère que le rendu initial des lignes est tout à fait correct, mais appeler resetAfterIndex est très difficile à gérer. Mes données changent (par exemple lorsque l'utilisateur sélectionne une conversation différente). Mais le vrai problème est que resetAfterIndex semble fonctionner avant que le nouveau setSize ne puisse se terminer. Il réussit donc à effacer le style mis en cache, mais il génère à nouveau un nouveau cache des anciens styles car le navigateur n'a pas fini de redimensionner le contenu.

Je ne sais pas si cela a du sens par écrit, mais je dois mettre une épingle dans celui-ci pour le moment. S'il vous plaît laissez-moi savoir si quelqu'un modifie avec succès son contenu de manière dynamique et maintient des styles de hauteur mis à jour.

J'ai beaucoup d'autres implémentations de react-window, donc je préférerais vraiment trouver une bonne solution ici au lieu d'utiliser react-virtualized pour ce cas d'utilisation.


EDIT 3: Ce sera ma dernière édition puisque j'ai enfin trouvé une solution semi-élégante.

1.) Si l'élément itemData doit changer (c'est-à-dire lorsque la conversation change), démontez l'ensemble component, puis remontez-le avec le nouveau itemData. Cela peut être fait en utilisant un rappel setState. Cela garantit que les anciens styles de hauteur ne sont pas reportés lorsque vous modifiez vos données.

2.) J'ai passé {sizeMap, setSize, listRef} à ChatMessage via ChatContext . De cette façon, au lieu de simplement définir la taille à l'aveugle, je peux dire à ChatMessage de définir la taille ET de la comparer à l'ancienne taille. Si l'ancienne taille est différente de la nouvelle taille, alors appelez un resetAfterIndex partir de index et en passant true pour forcer la mise à jour.

Donc, mon nouveau ChatMessage ressemble à ceci:

const ChatMessage = ({ message, index }) => {
    const { setSize, sizeMap, listRef } = useContext(ChatContext);
    const root = React.useRef();
    useEffect(() => {
        let oldSize = sizeMap[index];
        let newSize = root.current.getBoundingClientRect().height;
        setSize(index, newSize);
        if(newSize !== oldSize){
            listRef.current.resetAfterIndex(index,true);
        }
    }, [sizeMap, setSize, listRef]);

    return (
        <div ref={root}
             {message.body}
        </div>
    );
};
export default ChatMessage;

3.) J'ai ajouté ce qui est essentiellement un auditeur dans le composant qui attend le nouveau à rendre. Une fois rendu, il défile vers le bas. Cela résout le problème de la tentative de placer la fonction scrollTo directement dans componentDidMount car elle n'est jamais rendue avant que cette méthode ne soit appelée. Donc ressemble à ça:

class Chat extends Component {
    constructor(props) {
        super(props);
        this.listRef = createRef();
        this.state = {
            initialScrollComplete: false,
            interval: null
        };
    }

    componentDidMount(){
        // Create interval to check if list is ready. Once ready, scroll to bottom of list.
        this.setState({interval: setInterval(()=>{
            if(this.listRef.current && !this.state.initialScrollComplete){
                this.listRef.current.scrollToItem(this.props.chatHistory.length - 1, "end");
                this.setState({initialScrollComplete: true});
            }
        },25)});
    }

    componentDidUpdate(prevProps, prevState) {

        // Clear interval if scroll has been completed
        if(!prevState.initialScrollComplete && this.state.initialScrollComplete){
            clearInterval(this.state.interval);
            this.setState({interval: null});
        }

        // If new message is transmitted, scroll to bottom
        if(prevProps.chatHistory && this.props.chatHistory && prevProps.chatHistory.length !== this.props.chatHistory.length){
            this.listRef.current.scrollToItem(this.props.chatHistory.length - 1, "end");
        }

    }

    render() {
        return <ChatHistory listRef={this.listRef} chatHistory={this.props.chatHistory}/>;
    }
}

Il semble y avoir un comportement vraiment étrange en safari.

La hauteur du div DynamicSizedList et la hauteur ou la marge supérieure des lignes ne fonctionnent pas correctement, le contenu commence à se chevaucher.

Lorsque la largeur de la fenêtre / le contenu de la ligne change, la nouvelle hauteur n'est pas recalculée ou modifiée pour fonctionner avec la nouvelle hauteur du contenu.

Quelque chose qui semble résoudre ce problème, c'est si le contenu peut faire défiler, faire défiler jusqu'à un point où la ligne n'est plus visible, revenir en arrière pour le rendre correctement.

Le contenu ne s'affiche pas correctement lors du chargement de la première page, le rafraîchissement ne semble donc pas résoudre le problème: /

Tout fonctionne parfaitement sur d'autres navigateurs, y compris Chrome et Firefox. Safari est horrible, mais malheureusement, l'application doit toujours fonctionner pour les personnes qui l'utilisent.

Screenshot 2020-02-15 at 14 27 19

J'ai vraiment besoin d'aide!

@tastyqbit J'ai également rencontré le même problème sur Safari et Internet Explorer. Comme vous l'avez mentionné, faire défiler la ligne développée, puis revenir en arrière permet un rendu correct, mais bien sûr, cela ne résout pas vraiment le problème.

Si vous trouvez des solutions de contournement, faites-le moi savoir!

@afreix @tastyqbit Je suis assez certain que vos problèmes sur Safari et Internet Explorer sont dus au manque de support de ResizeObserver dans ces navigateurs. J'avais exactement votre problème (le défilement en arrière l'a corrigé) et l'ajout d'un polyfill l'a résolu pour moi. Voir MDN pour les tableaux de compatibilité.

Je pense que l'absence de ResizeObserver devrait générer un avertissement dans la console.

Qu'en est-il de quelque chose comme ça https://codesandbox.io/s/agitated-jennings-o9nn6 ?

basique en utilisant VariableSizeList + ItemMeasurer de # 102 Je sais que c'est une approche très naïve mais on dirait que cela fonctionne un peu (pas si mal 😂) comme solution temporaire 🤔

Dans notre équipe, nous avons rencontré le besoin de rendre une grande liste de données textuelles de taille aléatoire.
Pour nous, la capacité de sauter avec précision entre les éléments et de faire défiler sans aucun décalage était un must.
Après pas mal de recherches en ligne, j'ai abandonné et j'ai écrit cette bibliothèque .
J'espère que cela aidera comme solution temporaire pour certains d'entre vous: smile_cat:

Hey,
Je voulais juste mettre à jour qu'après un certain travail, je pense que la bibliothèque est arrivée dans un état décent et pourrait être une bonne solution si vos éléments ne changent pas de taille après avoir été rendus pour la première fois.

@ gnir-work et si la fenêtre se redimensionnait et que la taille du conteneur changeait entraînant le redimensionnement de la liste?

En lisant ce fil, je pense qu'il pourrait y avoir une meilleure façon de gérer les éléments dont la largeur peut changer.

La définition de «variable» ici est variable sur l'ensemble de l'ensemble. La taille réelle des éléments est statique et non dynamique. Peut-être que dynamique est un meilleur terme car la taille peut changer pendant le redimensionnement ou la mutation si le texte change.

La façon dont cela pourrait fonctionner est d'écouter le défilement sur le parent.

L'algorithme fonctionnerait comme ceci:

  • calculer une taille estimée pour chaque élément - cela doit être très efficace. Il n'est pas nécessaire que ce soit parfait. + - 20%, c'est bien.

  • nous ne rendons que les éléments visibles + disons 20% de plus, de sorte que si l'utilisateur fait défiler, il ne voit aucun changement

  • Nous avons un «fantôme» pour tout le reste dont la «hauteur» est définie sur la hauteur estimée. C'est juste un div vide. De cette façon, la barre de défilement semble à peu près droite.

  • Un élément n'est affiché que lorsqu'il se trouve dans la fenêtre. Autre que cela, les éléments fantômes sont affichés.

Le seul inconvénient est que la hauteur de la barre de défilement changera légèrement. Je ne sais pas si cela distrait l'utilisateur. Peut-être si la liste déroulante est grande. Nous pourrions être en mesure de tromper cela en augmentant / diminuant un tampon de sorte que les tailles estimées n'affectent pas la longueur de la barre de défilement.

@ gnir-work et si la fenêtre se redimensionnait et que la taille du conteneur changeait entraînant le redimensionnement de la liste?

À partir de la dernière version ( 2.2.0 ), le composant prend en charge les modifications de la taille de la liste entière (hauteur et largeur).

En lisant ce fil, je pense qu'il pourrait y avoir une meilleure façon de gérer les éléments dont la largeur peut changer.

La définition de «variable» ici est variable sur l'ensemble de l'ensemble. La taille réelle des éléments est statique et non dynamique. Peut-être que dynamique est un meilleur terme car la taille peut changer pendant le redimensionnement ou la mutation si le texte change.

La façon dont cela pourrait fonctionner est d'écouter le défilement sur le parent.

L'algorithme fonctionnerait comme ceci:

  • calculer une taille estimée pour chaque élément - cela doit être très efficace. Il n'est pas nécessaire que ce soit parfait. + - 20%, c'est bien.
  • nous ne rendons que les éléments visibles + disons 20% de plus, de sorte que si l'utilisateur fait défiler, il ne voit aucun changement
  • Nous avons un «fantôme» pour tout le reste dont la «hauteur» est définie sur la hauteur estimée. C'est juste un div vide. De cette façon, la barre de défilement semble à peu près droite.
  • Un élément n'est affiché que lorsqu'il se trouve dans la fenêtre. Autre que cela, les éléments fantômes sont affichés.

Le seul inconvénient est que la hauteur de la barre de défilement changera légèrement. Je ne sais pas si cela distrait l'utilisateur. Peut-être si la liste déroulante est grande. Nous pourrions être en mesure de tromper cela en augmentant / diminuant un tampon de sorte que les tailles estimées n'affectent pas la longueur de la barre de défilement.

Cela était déjà implémenté par @bvaughn dans react-virtualized . Le principal inconvénient de cette approche est que sauter à une ligne spécifique ne fonctionne pas bien et crée des bogues visuels lors du défilement vers le haut.

@ gnir-work ah .. ok ... peut-être que je vais abandonner mon travail et regarder réagir-virtualisé.

Je pense que vous avez raison avec les problèmes de défilement, mais je pense que je peux résoudre ce problème en ayant une `` taille estimée '', puis la convertir en taille réelle une fois le composant monté.

... mais un autre problème bien sûr est la gestion du contenu dynamique. Si quelque chose met à jour la hauteur du composant change.

Si la taille estimée est précise que cela peut fonctionner, par exemple, j'ai implémenté il y a quelque temps une liste virtualisée avec une hauteur dynamique avec react-virtualized et cela fonctionnait bien tant que la taille estimée était exacte. Sinon, la fonctionnalité de défilement vers la ligne casserait mon application ☹

Envoyé de Mail pour Windows 10

De: Kevin Burton
Envoyé: mardi 14 avril 2020 23:07
À: bvaughn / react-window
Cc: Nir Geller; Mention
Objet: Re: [bvaughn / react-window] Prise en charge du contenu mesuré juste à temps (# 6)

@ gnir-work ah .. ok ... peut-être que je vais abandonner mon travail et regarder réagir-virtualisé.
Je pense que vous avez raison avec les problèmes de défilement, mais je pense que je peux résoudre ce problème en ayant une `` taille estimée '', puis la convertir en taille réelle une fois le composant monté.
... mais un autre problème bien sûr est la gestion du contenu dynamique. Si quelque chose met à jour la hauteur du composant change.
-
Vous recevez cela parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub ou désabonnez-vous.

-
Cet e-mail a été vérifié pour les virus par le logiciel antivirus Avast.
https://www.avast.com/antivirus

@ gnir-work ah ... Je n'ai pas besoin de la fonctionnalité "scroll to row" je pense ... même si je me trompe peut-être.

Que cela devrait suffire à vos besoins 😊

Envoyé de Mail pour Windows 10

De: Kevin Burton
Envoyé: mardi 14 avril 2020 23:13
À: bvaughn / react-window
Cc: Nir Geller; Mention
Objet: Re: [bvaughn / react-window] Prise en charge du contenu mesuré juste à temps (# 6)

@ gnir-work ah ... Je n'ai pas besoin de la fonctionnalité "scroll to row" je pense ... même si je me trompe peut-être.
-
Vous recevez cela parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub ou désabonnez-vous.

-
Cet e-mail a été vérifié pour les virus par le logiciel antivirus Avast.
https://www.avast.com/antivirus

Comme solution de contournement si:

  • la hauteur de la ligne de votre liste dépend uniquement du texte intérieur (plus peut-être de certains éléments avec des dimensions déterminées)
  • et votre liste a une largeur fixe

vous pouvez utiliser CanvasRenderingContext2D.measureText () pour calculer la hauteur de ligne au lieu de rendre le composant entier: caca:

CodeSandbox

@bvaughn Avez -vous l'intention de publier une nouvelle version alpha sur npm? Nous n'avons eu aucune mise à jour depuis 1.6.0-alpha.1 😕

@bvaughn des mises à jour? sera-t-il corrigé dans les versions récentes?

Pour ceux qui souhaitent utiliser Typescript avec DynamicSizeList - l'augmentation de module peut donner les types nécessaires pour DynamicSizeList fonctionnant à partir des définitions DefinatelyTyped (une solution de contournement à ma requête publiée dans ce fil l'année dernière).

Ajoutez ce qui suit au projet:

import React, { Component } from 'react'

declare module 'react-window' {
  export type DynamicSizeListProps = Omit<FixedSizeListProps, 'itemSize' | 'scrollToItem'>
  export class DynamicSizeList extends Component<DynamicSizeListProps> {}
}

Puis importez comme d'habitude:

import {
  DynamicSizeList,
  DynamicSizeListProps,
} from 'react-window'

// use as normal...

@types/react-window doit encore être installé en premier pour la définition FixedSizeListProps .

Merci pour les typedefs, je vais les ajouter maintenant! J'utilise DynamicSizeList en production depuis plus d'un an maintenant. Actuellement basé sur ce fork: "@john-osullivan/react-window-dynamic-fork": "^1.9.0-alpha.1" (est-ce encore la chose la plus à jour?). J'ai essayé de passer à react-virtuoso raison de l'incertitude quant à savoir si / quand cela serait réellement publié. Mais je l'ai trouvé moins performant et coincé avec ça.

@bvaughn est-il encore temps d'ouvrir le chemin des vaches et de le remettre à npm? Peut-être simplement renommé en ExperimentalDynamicSizeList si vous craignez toujours qu'il ne soit pas prêt.

Bonjour gars! Merci pour votre travail acharné et cette formidable bibliothèque. J'attends vraiment cette fonctionnalité avec impatience! Cependant, je suggérerais d'ajouter des informations concernant ce problème au README et à la documentation / exemples. Il m'a fallu un certain temps pour comprendre que le contenu dynamique n'est pas réellement pris en charge par la bibliothèque et qu'il n'est utile que pour les éléments de taille fixe / connue. Je crois que le README a une belle section FAQ où cela pourrait être ajouté.

si vous recherchez une table / grille / arbre, ce serait un bon début https://autodesk.github.io/react-base-table/examples/dynamic-row-heights , construit sur VariableSizeGrid

@ tony-scio pouvez-vous s'il vous plaît partager un code et une boîte de travail pour utiliser DynamicSizeList de 1.6.0-alpha.1 avec InfiniteLoader? Merci, je l'apprécierais vraiment.

Quelqu'un a-t-il réussi à faire fonctionner cela avec react-beautiful-dnd? Faire glisser semble faire sauter les éléments les uns sur les autres.

Quelqu'un a-t-il réussi à faire fonctionner cela avec react-beautiful-dnd? Faire glisser semble faire sauter les éléments les uns sur les autres.

j'attendrai aussi cette réponse: D

[AIDER]
Il n'y a pas de code pour montrer sur ce lien:
liste-taille-dynamique-verticale
et j'ai besoin de cette capacité.
MERCI

[AIDER]
Il n'y a pas de code pour montrer sur ce lien:
liste-taille-dynamique-verticale
et j'ai besoin de cette capacité.
MERCI

https://react-window-next.now.sh/#/examples/list/dynamic -size

Une mise à jour pour ceci? Nous avons besoin de quelque chose de similaire que nous pouvons (c'est généralement très peu, mais dans certains cas, cela peut être beaucoup) pour rendre une grande liste d'éléments en grille réactive (leurs hauteurs sont dynamiques et changeront sur le mobile au fur et à mesure que divers habillages de texte, etc.). Je pense que react-window changerait la donne s'il pouvait gérer ce cas d'utilisation. Sinon, existe-t-il des alternatives fiables?

Une mise à jour pour ceci? Nous avons besoin de quelque chose de similaire que nous pouvons (c'est généralement très peu, mais dans certains cas, cela peut être beaucoup) pour rendre une grande liste d'éléments en grille réactive (leurs hauteurs sont dynamiques et changeront sur le mobile au fur et à mesure que divers habillages de texte, etc.). Je pense que react-window changerait la donne s'il pouvait gérer ce cas d'utilisation. Sinon, existe-t-il des alternatives fiables?

@JavaJamie puisque vous avez spécifiquement demandé des alternatives - la bibliothèque react -virtuoso est livrée avec un support intégré pour mesurer le contenu dynamique. Avertissement: J'en suis l'auteur.

@JavaJamie puisque vous avez spécifiquement demandé des alternatives - la bibliothèque react -virtuoso est livrée avec un support intégré pour mesurer le contenu dynamique. Avertissement: J'en suis l'auteur.

react-virtuoso est également le double de la taille de react-window. Il faut toujours garder à l'esprit la taille de la dépendance.

https://bundlephobia.com/[email protected]
https://bundlephobia.com/[email protected]

J'ai accepté le fait que je n'ai ni le temps ni l'énergie pour terminer cet effort. Si quelqu'un souhaite intervenir et terminer la branche que j'ai créée, je serais ravi de votre aide. (Veuillez également consulter le numéro 302 pour savoir comment cela s'intégrerait dans la version deux en tant que nouveaux composants List et Grid .)

Nous avons fini par implémenter quelque chose à partir de zéro pour cela, qui a utilisé des capteurs de visibilité qui fonctionnaient très bien.

Je pourrais probablement OSS ou vous diriger vers le bon endroit si vous voulez le déchirer et créer un nouveau projet ou le déplacer ici.

Une astuce consiste à utiliser des «blocs» pour augmenter les performances. Fondamentalement, nous prenons chaque ligne et la plaçons dans un bloc parent de 25 éléments similaires, puis nous les échangeons si nécessaire.

@burtonator ce serait vraiment utile

Quelqu'un peut-il fournir une implémentation sans bogue de react-select avec DynamicSizeList?
Je n'arrive pas à bien faire fonctionner ensemble.
Actuellement, je rencontre 2 problèmes (désolé pour aucune capture d'écran):

  1. Tous les éléments ont style={position: absolute, left: 0, top: 0} ce qui ne me permet pas d'utiliser ce style car toutes les options se superposent.
  2. Si je n'utilise pas l'accessoire de style, la liste s'affiche bien, mais lorsque je défile un peu, la partie de la liste contenant des options se réduit, tandis que la hauteur totale reste inchangée. Ainsi, lorsque je fais défiler, j'obtiens x pixels d'options réelles et un espace blanc de longueur x pixels.

Impossible de trouver un exemple fonctionnel des deux.
Je noterai que j'utilise la fourche 1.9.0, sur Chrome.

Éditer. J'ai trouvé une réponse ci-dessus, dans la section des commentaires cachés. https://github.com/bvaughn/react-window/issues/6#issuecomment -509016422

Une simplification du problème de défilement consisterait à utiliser la barre de défilement pour indiquer l'index de l'élément dans la liste au lieu d'une position de pixel, si le défilement est éloigné de plus d'une hauteur de fenêtre. Au lieu d'essayer de «faire défiler vers le bas» X pixels, le composant restitue simplement les éléments autour de l'index souhaité. À mi-chemin, rend l'élément à l'index N / 2, et en bas rend l'élément à l'index N-1.

Cela permettrait un défilement direct du pouce vers le milieu ou la fin de la liste, sans le retard du pouce de défilement pendant que le composant rend et calcule les tailles. À l'heure actuelle, pour les composants VariableSizeList très longs, il est presque impossible de faire défiler vers le bas car le curseur se déplace plus vite que le pouce de défilement.

Cette page vous a été utile?
0 / 5 - 0 notes