Wie kann ich am einfachsten Engpässe in der Renderleistung von React identifizieren?

Aug 15 2020

Ich habe ein Problem mit der Identifizierung von Engpässen in der Renderleistung, während ich an einem JSON-Viewer arbeite. Mit wenigen Elementen funktioniert es gut, aber an einem bestimmten Punkt wird es ärgerlich langsam.

Beim Überprüfen des Profilers scheint es, dass Elemente schnell genug gerendert werden, aber ich habe einige Probleme festgestellt, bei denen ich nicht sicher bin, wie ich sie angehen soll.

Überblick

  • Die App ist ein JSON-Viewer, mit dem Sie alle Elemente auf einmal sowie einzelne Elemente erweitern / minimieren können.
  • Die Leistung ist mit wenigen Elementen in Ordnung, scheint aber mit zunehmender Anzahl von Elementen dramatisch abzunehmen.
  • Beim Profilieren sowohl meiner performance.now()Objektfiltermethode als auch beim Überprüfen der Renderzeit in React DevTools scheinen die Zahlen in Ordnung zu sein. Ich könnte es falsch interpretieren.
  • Ich habe versucht, React.memo()zustandslose Elemente zu verwenden (insbesondere den Schlüssel/Wert, der die am häufigsten gerenderte Komponente ist), aber es scheint die Leistung nicht merklich zu verbessern. Zugegebenermaßen bin ich mir nicht sicher, ob ich die Gründe für das Auswendiglernen von React-Komponenten ausreichend verstehe, um dies sinnvoll zu implementieren.

Implementierung

  • Derzeit lädt meine App Daten in ein übergeordnetes Element, das in eine Komponente eingespeist wird, die den JSON-Baum mithilfe eines rekursiven Elements lädt.
  • Das Laden des JSON-Feeds von der URL ändert den Status der übergeordneten Komponente, die mithilfe einer Hilfsmethode gefiltert wird, die in ein Eingabefeld eingegebene Werte verwendet.

Ausgaben

Es gibt zwei Funktionalitäten, die eine langsame Antwortzeit mit (nicht so großen) JSON-Dokumenten reproduzieren:

  • Die Schaltfläche Alle erweitern
  • Die ersten paar Tastendrücke bei einer Filterabfrage

Bei der aktuellen Implementierung löst sowohl das Filtern als auch das Erweitern von allen eine display: noneÄnderung an den untergeordneten Elementen aus, und das Verhalten lässt mich glauben, dass ich etwas ineffizient tue, um diesen Anwendungsfall zu handhaben.

Reproduktionsschritte

Den Code gibt es hier:https://codesandbox.io/s/react-json-view-4z348

Mit einem Produktions-Build hier (nicht besser):https://csb-4z348.vercel.app/

Um das Problem zu reproduzieren, spielen Sie mit der Funktion Alle erweitern (Pluszeichen neben der Filtereingabe) und einigen Filtereingaben herum.

Versuchen Sie dann, einen JSON-Feed mit mehr Elementen zu laden (Sie können dies in meinem GitHub-API-Feed testen ) und versuchen Sie, alle zu filtern/erweitern. Beachten Sie den großen Leistungseinbruch.

Was mir aufgefallen ist

  • Beim Protokollieren von useEffect scheint das Minimieren etwa 2-mal so viele Neudarstellungen zu verursachen wie das Erweitern aller.
  • Wenn die Filtereingabe spezifischer wird, verbessert sich (logischerweise) die Leistung, da weniger Elemente gerendert werden.

Frage

Ich würde mich zwar über einen Schubs in die richtige Richtung für diesen speziellen Fall freuen, aber was mich am meisten interessiert, ist, wie man am besten identifiziert, was diese Leistungsprobleme verursacht.

Ich habe versucht, die Ausgabe zu fenstern, aber es ist nicht meine erste Wahl, und ich bin mir ziemlich sicher, dass ich etwas falsch mache, anstatt dass die Ursache zu viele gerenderte Elemente sind.

Ich schätze Ihre Zeit und danke Ihnen im Voraus für alle Tipps, die Sie geben könnten!

Antworten

2 HarrisonGrieve Aug 16 2020 at 15:50

Anscheinend habe ich meine eigene Frage beantwortet. Das Problem war ein Abstimmungsproblem aufgrund der Verwendung von UUID als Schlüsselstütze in meinen untergeordneten Komponenten, was dazu führte, dass sie jedes Mal neu gerendert wurden, wenn sich der Minimierungsstatus änderte. Aus den Dokumenten:

Schlüssel sollten stabil, vorhersagbar und eindeutig sein. Instabile Schlüssel (wie die von Math.random() erzeugten) führen dazu, dass viele Komponenteninstanzen und DOM-Knoten unnötig neu erstellt werden, was zu Leistungseinbußen und Zustandsverlusten in untergeordneten Komponenten führen kann.

Ich lasse die Schritte hier für alle anderen, die auf dieses Problem stoßen.


Nachdem ich (zu lange) im Leistungsprofiler herumgegraben hatte, bemerkte ich, dass jedes Mal, wenn ich die Elemente minimierte oder erweiterte, jedes untergeordnete Element erneut eingehängt wurde. Nachdem ich Google mit einer spezifischeren Anfrage konsultiert hatte, fand ich diesen Blog-Beitrag und stellte fest, dass ich diesen offensichtlichen Leistungsfehler beging.

Nachdem ich die Ursache des Problems gefunden hatte, fand ich viele andere Hinweise darauf.

Nach dem Reparieren der Schlüssel-Requisite wurde die Interaktionszeit beim Minimieren/Erweitern von allen um ca. 60 % schneller.

Schließlich habe ich einige andere Komponenten im Zusammenhang mit dem Sofortfilter auswendig gelernt, und schließlich scheint er vorerst so gut zu funktionieren, wie ich es gerne hätte.

Vielen Dank an alle, die sich dies in der Zwischenzeit angesehen haben, und ich hoffe, es ist hilfreich für alle, die darauf stoßen könnten.