Comment puis-je identifier le plus facilement les goulots d'étranglement dans les performances de rendu de React ?

Aug 15 2020

J'ai un problème avec l'identification des goulots d'étranglement dans les performances de rendu lorsque je travaille sur une visionneuse JSON. Avec peu d'éléments, il fonctionne bien, mais à un certain point, il devient extrêmement lent.

En vérifiant le profileur, il semble que les éléments soient rendus assez rapidement, mais j'ai remarqué quelques problèmes que je ne sais pas comment poursuivre.

Aperçu

  • L'application est une visionneuse JSON qui vous permet de développer / minimiser tous les éléments à la fois, ainsi que des éléments individuels.
  • Les performances sont correctes avec peu d'éléments, mais semblent diminuer considérablement à mesure que le nombre d'éléments augmente.
  • Lors du profilage de ma méthode de filtrage d'objets performance.now()et de la vérification du temps de rendu dans React DevTools, les chiffres semblent corrects. Je l'interprète peut-être mal.
  • J'ai essayé d'utiliser React.memo()des éléments sans état (en particulier la clé/valeur qui est le composant le plus fréquemment rendu), mais cela ne semble pas améliorer sensiblement les performances. Certes, je ne suis pas sûr de comprendre suffisamment le raisonnement derrière la mémorisation des composants React pour implémenter cela utilement.

Mise en œuvre

  • Actuellement, mon application charge des données dans un parent qui alimente un composant qui charge l'arborescence JSON à l'aide d'un élément récursif.
  • Le chargement du flux JSON à partir de l'URL modifie l'état du composant parent, qui est filtré à l'aide d'une méthode d'assistance qui utilise des valeurs entrées dans un champ de saisie.

Problèmes

Il existe deux fonctionnalités qui reproduisent un temps de réponse lent avec des documents JSON (pas si gros) :

  • Le bouton Développer tout
  • Les premières pressions sur une requête de filtre

Avec l'implémentation actuelle, le filtrage et l'expansion de tous déclenchent une display: nonemodification des éléments enfants, et le comportement me porte à croire que je fais quelque chose d'inefficace pour gérer ce cas d'utilisation.

Étapes de reproduction

Le code est disponible ici :https://codesandbox.io/s/react-json-view-4z348

Avec une version de production ici (qui ne fonctionne pas mieux):https://csb-4z348.vercel.app/

Pour reproduire le problème, jouez avec la fonction Développer tout (signe plus à côté de l'entrée de filtre) et certaines entrées de filtre.

Ensuite, essayez de charger un flux JSON avec plus d'éléments (vous pouvez tester sur mon flux API GitHub ) et essayez de filtrer/étendre tout. Remarquez le principal impact sur les performances.

Ce que j'ai remarqué

  • Lors de la journalisation de useEffect, la minimisation semble provoquer environ 2 fois plus de rendus que l'expansion de tous.
  • Au fur et à mesure que l'entrée du filtre devient plus spécifique, les performances (logiquement) s'améliorent car moins d'éléments sont rendus.

Question

Bien que j'apprécierais un coup de pouce dans la bonne direction pour ce cas spécifique, ce qui m'intéresse le plus, c'est de savoir comment identifier au mieux la cause de ces problèmes de performances.

J'ai cherché à fenêtrer la sortie, mais ce n'est pas mon premier choix, et je suis presque sûr que je fais quelque chose de mal, plutôt que la cause étant trop d'éléments rendus.

Je vous remercie de votre temps et vous remercie d'avance pour les conseils que vous pourriez fournir !

Réponses

2 HarrisonGrieve Aug 16 2020 at 15:50

Il semble que j'ai répondu à ma propre question. Le problème était un problème de réconciliation dû à l' utilisation de l'UUID comme accessoire clé dans mes composants enfants, ce qui les obligeait à se restituer à chaque fois que l'état de réduction changeait. À partir de la documentation :

Les clés doivent être stables, prévisibles et uniques. Les clés instables (comme celles produites par Math.random()) entraîneront la recréation inutile de nombreuses instances de composants et de nœuds DOM, ce qui peut entraîner une dégradation des performances et une perte d'état dans les composants enfants.

Je vais laisser les étapes ici pour toute autre personne qui rencontre ce problème.


Après avoir fouillé (trop longtemps) dans le profileur de performances, j'ai remarqué qu'à chaque fois que je minimisais ou développais les éléments, chaque enfant était à nouveau monté. Après avoir consulté Google avec une requête plus spécifique, j'ai trouvé ce billet de blog et j'ai réalisé que je commettais cette erreur de performance flagrante.

Une fois que j'ai trouvé la source du problème, j'ai trouvé de nombreuses autres références à celui-ci.

Après avoir corrigé l'accessoire clé, le temps d'interaction a été d'environ 60 % plus rapide pour minimiser/développer tout.

Enfin, j'ai mémorisé d'autres composants liés au filtre instantané et finalement il semble fonctionner aussi bien que je le souhaiterais pour le moment.

Merci à tous ceux qui ont jeté un coup d'œil à cela entre-temps, et j'espère que cela sera utile à tous ceux qui pourraient rencontrer cela.