Nested-loop Reagiere Komponenten mit Flux, change-listeners für Eltern oder Kinder?

8

Ich baue einen Word-Dojo-Klon in React / Flux. Das Spiel ist im Wesentlichen Boggle - Sie machen Wörter durch Klicken auf benachbarte Buchstaben in einem Raster:

Meine React-Komponenten mit ihrer Quelle:

  1. Spielbrett
  2. TileColumn
  3. Fliese

Der gesamte Quellcode kann hier angezeigt werden.

Wie es jetzt funktioniert :

Es gibt einen GameStore , der ein zweidimensionales Array enthält Javascript-Objekte. Die Objekte haben einen "Buchstaben" -String-Wert und einen "aktiven" booleschen Wert. Wenn der Benutzer auf einen Buchstaben klickt, wird dieser an den GameStore gesendet, der dieses zweidimensionale Array aktualisiert und ein Change-Ereignis ausgibt.

Die GameBoard-Komponente wartet auf dieses Änderungsereignis und rendert dann 10 TileColumns erneut, die wiederum jeweils 10 Tiles rendern. GameBoard hat die Daten des Geschäfts als Teil seines Status und Kacheln haben ihren eigenen Buchstaben / aktiven Status als Requisiten.

Das Problem ist, dass die Änderung von einem Buchstaben dazu führt, dass alle 100 Kacheln erneut gerendert werden.

sollteComponentUpdate

Ich habe versucht, mithilfe von sollteComponentUpdate auf der Kachel anzugeben, dass sie nur aktualisiert werden soll, wenn der 'aktive' Wert sich geändert hat, aber das Problem ist, dass sowohl this.props.active als auch nextProps.active immer denselben Wert haben: entweder ' beides falsch oder beides wahr.

Verantwortung auf die Kinder übertragen

Die andere Idee, die ich hatte, war, jedes Kachel für seine eigene Aktualisierung verantwortlich zu machen, indem ich die Listener auf den Kacheln direkt registrierte. Ich bekam eine Warnung, dass ich die Anzahl der Zuhörer überschritt, und es sieht so aus, als ob 100 Zuhörer alle, die auf jedes Brief-Update feuern würden, weniger effizient wären. Obwohl das alles nur Javascript ist, würden wir einige DOM-Manipulationen vermeiden ...

Leistung

Ich habe den Profiler hochgefahren und gerade jetzt, mit dem Elternteil, der die gesamte Staatsverwaltung erledigt, dauert es 40 ms, um das ganze Board mit einem Buchstabenklick neu zu rendern. Was nicht schlimm ist, aber wenn das Spiel komplizierter wird, mache ich mir Sorgen, dass es eine merkliche Verzögerung wird.

Hilfe benötigt

Insbesondere suche ich Ratschläge zu Best Practices in dieser Situation (wenn Sie verschachtelte, iterierte Komponenten haben) und wenn sollteComponentUpdate ist die Lösung, aber ich benutze es einfach falsch.

Danke!

    
Joshua Comeau 20.03.2015, 12:21
quelle

1 Antwort

12

Ja, das ist das klassische Beispiel dafür, warum React standardmäßig nicht schnell ist. Ich habe ein ziemlich langes Beispiel hier für genau welche Art von Problem Sie versuchen zu lösen.

Grundsätzlich haben Sie zwei typische Probleme:

  1. Wie Sie die Kacheln auf dem Server initialisieren Board ist in Ordnung, aber die Art, wie Sie ändern Werte für die Kachel mutieren das Objekt einfach. Dies macht es schwierig zu wissen, ob sich ein bestimmtes Objekt geändert hat.

  2. Reagiert naiv und berechnet die gesamte Anwendung standardmäßig neu. Sie können eine teure Neuberechnung von Elementen mit render () nur verhindern, wenn Sie shouldComponentUpdate intelligent verwenden.

Lösung:

Verwenden Sie shouldComponentUpdate (oder verwenden Sie einfach ReactComponentWithPureRenderMixin ), um eine unnötige Neuberechnung in Tile zu verhindern. Natürlich funktioniert nicht , wenn Sie nicht ein paar Dinge tun.

Lösungen sind:

  1. Sie wissen, welche Eigenschaften mutiert werden dürfen, und richten shouldComponentUpdate basierend auf diesen ein.

Darf nur tile.active geändert werden? Sie können möglicherweise nur Ihren Rückruf definieren , sodass Sie nur nach dem suchen Gleichheit von prevProps.tile.active === this.props.tile.active .

  1. Erstellen Sie ein neues Objekt, so dass der oberflächliche Vergleich von Objektreferenzen einfach ist.

Sie wissen wahrscheinlich bereits, dass var a = {}; var b = a es so macht, dass a === b , und dass var c = {}; var d = {}; es so macht, dass c !== d . Ersetzen Sie das Kachelobjekt bei jeder Aktualisierung vollständig, damit Sie das neue Kachelobjekt verwenden können, in dem sich das alte befand. Auf diese Weise ist eine schnelle Leistung buchstäblich nur mixins: [ReactComponentWithPureRenderMixin] weg.

Das könnte viel schäbiger sein, als du wolltest, aber es ist genau so, wie ich jede Art von Sammlung in React gut rendern kann. Ohne diese Techniken kann ich meine meine schlechte Etch-a-sketch-Komponente buchstäblich nicht zum Laufen bringen.

Viel Glück!

    
kakigoori 20.03.2015, 13:25
quelle