Ich schreibe eine einfache App auf reactjs-flux und alles funktioniert gut, außer dass ich eine Warnung von reactjs erhalte, die mir sagt, dass ich setState auf nicht eingebundenen Komponenten anrufe.
Ich habe herausgefunden, dass Change-Listener, an die Komponenten angehängt sind, nicht aus dem Store von componentWillUnmount
entfernt werden. Ich weiß es, weil, wenn ich die Liste der Listener von Eventemitter
drucke, sehe ich den Listener, der zerstört werden sollte, immer noch dort, und die Liste wird größer, wenn ich die gleiche Komponente mehrmals mounte / unmount.
Ich füge Code aus meinem BaseStore ein:
%Vor%Ich füge den relevanten Code von einer Komponente ein, die diesen Fehler hat (es passiert jedoch mit allen Komponenten):
%Vor%Das macht mich jetzt ziemlich verrückt. Irgendwelche Ideen?
Danke!
Kurzversion: expect(f.bind(this)).not.toBe(f.bind(this));
Längere Erklärung:
Die Ursache des Problems ist, dass EventEmitter.removeListener
erfordert, dass Sie eine Funktion übergeben, die Sie zuvor mit EventEmitter.addListener
registriert haben. Wenn Sie einen Verweis auf eine andere Funktion übergeben, handelt es sich um ein stilles No-Op.
In Ihrem Code übergeben Sie this._onChange.bind(this)
an addListener. bind
gibt eine neue Funktion zurück, die an diese gebunden ist. Sie verwerfen dann den Verweis auf diese gebundene Funktion. Dann versuchen Sie, eine andere neue Funktion zu entfernen, die durch einen Bind-Aufruf erstellt wurde, und es ist ein No-Op, da dieser nie hinzugefügt wurde.
React.createClass bindet automatisch Methoden ein. In ES6 müssen Sie Ihren Konstruktor manuell binden:
Es gibt verschiedene Möglichkeiten, die Bindung zu vereinfachen: Sie können einen ES7 @autobind
Methoden-Decorator (z. B. autobind-decorator auf npm) verwenden oder eine automatische Bindungsfunktion schreiben, die Sie im Konstruktor mit autoBind(this);
aufrufen.
In ES7 können Sie (hoffentlich) Klasseneigenschaften für eine bequemere Syntax verwenden. Sie können dies in Babel aktivieren, wenn Sie als Teil des Vorschlags der Stufe 1 Ссылка möchten. Dann deklarieren Sie Ihre Event-Listener-Methoden einfach als Klasseneigenschaften und nicht als Methoden:
%Vor% Da der Initialisierer für _onChange im Kontext des Konstruktors aufgerufen wird, bindet die Pfeilfunktion this
automatisch an die Klasseninstanz, sodass Sie this._onChange
einfach als Ereignishandler übergeben können, ohne sie manuell binden zu müssen.
Also habe ich die Lösung gefunden, es stellte sich heraus, dass ich this._onChange.bind(this)
nur einer internen Eigenschaft zuweisen musste, bevor ich es als Argument an removechangelistener
und addchangelistener
übergab. Hier ist die Lösung:
Ich weiß jedoch nicht, warum dies das Problem löst. Irgendwelche Ideen?
Ich verwende genau dieselbe Implementierung für mehrere reaktive Komponenten. Dies wird für mehrere .jsx-Komponenten wiederholt.
%Vor%Mögliche Lösung
Momentan funktioniert das Folgende für mich, aber es war ein bisschen temperamentvoll. Wickeln Sie den Aufruf in eine Funktion / benannte Funktion zurück.
%Vor%könnte man auch versuchen
%Vor%Theorie
EventEmitter ist aus irgendeinem Grund verwirrt, weil er den zu entfernenden Rückruf identifiziert. Die Verwendung einer benannten Funktion hilft vielleicht dabei.
Versuchen Sie, den .bind(this)
von Ihrem addChangeListener
und removeChangeListener
zu entfernen. Sie sind bereits an Ihre Komponente gebunden, wenn sie angerufen werden.
Dies ist ein es6 Problem. React.createClass bindet 'this' ordnungsgemäß für alle Funktionen, die in seinem Bereich definiert sind.
Für es6 musst du selbst etwas tun, um das richtige "Dies" zu binden. Calling bind (dies) erstellt jedoch jedes Mal eine neue Funktion, und die Rückgabe des Rückgabewerts an removeChangeListener stimmt nicht mit der Funktion überein, die an addChangeListener übergeben wurde, die durch einen früheren bind (this) -Aufruf erstellt wurde.
Ich sehe hier eine Lösung, wo bind (this) einmal für jede Funktion aufgerufen wird und der Rückgabewert gespeichert und später wieder verwendet wird. Das wird gut funktionieren. Eine beliebtere und etwas sauberere Lösung ist die Pfeilfunktion von es6.
%Vor%Pfeilfunktionen erfassen das 'Dies' des umgebenden Kontexts, ohne jedes Mal neue Funktionen zu erstellen. Es ist für solche Sachen entworfen.
Da Sie die Lösung hier bereits kennen gelernt haben, werde ich versuchen zu erklären, was passiert.
Gemäß dem ES5-Standard haben wir den folgenden Code geschrieben, um Listener hinzuzufügen und zu entfernen.
Im obigen Code ist die Speicherreferenz für die Callback-Funktion (dh: this._updateStore) gleich. RemoveChangeListener sucht nach einer Referenz und entfernt sie.
Da dem ES6-Standard standardmäßig die automatische Bindung this
fehlt, müssen Sie this
explizit an die Funktion binden.
Note: Bind method returns new reference for the callback.
Weitere Informationen zu bind
Hier tritt das Problem auf. Wenn wir this._updateStore.bind(this)
ausführen, gibt die bind-Methode eine neue Referenz für diese Funktion zurück. Die Referenz, die Sie als Argument an addChangeListener gesendet haben, ist also nicht dieselbe wie die in der removeChangeListener-Methode.
this._updateStore.bind(this) != this._updateStore.bind(this)
Lösung:
Es gibt zwei Möglichkeiten, dieses Problem zu lösen.
1. Speichern Sie den Ereignishandler (ie: this._updateStore)
im Konstruktor als Elementvariable. (Ihre Lösung)
2. Erstellen Sie im Geschäft eine benutzerdefinierte ChangeListener-Funktion, die this
für Sie bindet. (Quelle: hier )
Lösung 1:
%Vor% Im obigen Code binden wir this
an die _updateStore-Funktion und weisen diese einem Member innerhalb des Konstruktors zu. Später verwenden wir diesen Member, um den Change Listener hinzuzufügen und zu entfernen.
Lösung 2:
In dieser Methode modifizieren wir BaseStore-Funktionalitäten. Die Idee ist, die Funktion addChangeListener im BaseStore zu modifizieren, um das zweite Argument this
zu erhalten. Innerhalb dieser Funktion binden wir this
an den Callback und speichern diesen Verweis, so dass wir beim Entfernen des Change Listeners diesen Verweis entfernen können.
Hier finden Sie den vollständigen Code und die Quelle hier .
Tags und Links reactjs reactjs-flux flux