2016-06-28 19 views
4

Das Problem:Race-Bedingung in React setState

Mehrere Kinder eines Bauteils werden mit Veranstaltungen in der Nähe von gleichzeitig ausgelöst. Jedes dieser Ereignisse wird von handleChange Style-Funktionen gehandhabt, die Reacts Unveränderlichkeitshelfer verwenden, um komplexe Objekte in den Zustand der steuernden Komponente zu migrieren, ähnlich wie bei;

this.setState(React.addons.update(this.state, {$merge: new_value_object})); 

Dies funktioniert gut, wenn die Ereignisse unabhängig auslösen, aber wenn mehrere Ereignisse Updates an den Staat auf diese Weise führen, die jeweils einzeln von der alten Version des Staates zu verschmelzen. I.e. (Pseudo-Code, nicht zur Ausführung bestimmt).

function logState() { console.log(this.state) } 

logState(); // {foo: '', bar: ''} 

var next_value_object_A = {foo: '??'} 
var next_value_object_B = {bar: '!!'} 

this.setState(React.addons.update(this.state, {$merge: new_value_object_A}), 
    logState); 
this.setState(React.addons.update(this.state, {$merge: new_value_object_B}), 
    logState); 

Würde produzieren;

{foo: '??', bar: ''} 
{foo: '', bar: '!!'} 

Terrible Lösung, die ich will nicht verwenden:

Die folgende scheint zu funktionieren, aber es scheint auch ein großes anti-Muster zu sein;

setSynchronousState: function(nextState){ 
    this.state = React.addons.update(this.state, {$merge: nextState}); 
    this.setState(this.state); 
} 

Dies beruht auf der Änderung des Status direkt. Ich sehe keine unmittelbaren Probleme bei der Ausführung dieses Codes, und es löst das vorliegende Problem, aber ich muss mir vorstellen, dass ich mit dieser Lösung massive technische Schulden erwerbe.

Eine etwas bessere Version dieser Lösung ist;

getInitialState: function(){ 
    this._synchronous_state = //Something 
    return this._synchronous_state; 
}, 

_synchronous_state: {}, 

setSynchronousState: function(nextState){ 
    this._synchronous_state = React.addons.update(this._synchronous_state, {$merge: nextState}); 
    this.setState(this._synchronous_state); 
} 

die erfolgreich this.state direkt vermeidet zu berühren, obwohl wir jetzt die Frage der widersprüchlichen Informationen haben um die Anwendung übergeben werden. Jede andere Funktion muss nun davon abhängig sein, ob sie auf this.state oder this._synchronous_state zugreift.

Die Frage:

Gibt es einen besseren Weg, um dieses Problem zu lösen?

+1

Warum stellen Sie den Status als Zustandsaktualisierung ein? Setzen Sie den Status direkt: 'this.setState ({someKey: 'someVal'});' Dies löst Ihr Race-Problem, verringert die Größe Ihres Pakets und macht Ihren Code viel einfacher zu lesen. Das 'update' Addon ist für unveränderliche Objekte gedacht. Der Status einer Komponente ist kein unveränderliches Objekt - sie ist ein normales JS-Objekt, das unveränderliche Objekte enthalten kann oder auch nicht. –

+0

React-Dokumente behaupten, dass der Status als unveränderliches Objekt behandelt werden sollte. Das Zusammenführen erfolgt als ein Mittel, um Felder dynamisch aus mehreren Quellen zu setzen, anstatt 50 eindeutige "handleChange" -Funktionen in einer Komponente zu haben, um die große Anzahl von potentiellen Benutzereingaben zu bewältigen. – gravityplanx

+0

Das Schlüsselwort dort ist * gedacht *. Es ist jedoch kein 'immutable.js' Objekt. Sie sollten 'this.state' niemals direkt ändern, nur über' this.setState() ' –

Antwort

7

Beantworten meiner eigenen Frage für den Fall, dass jemand anderes dies sieht;

this.setState kann eine Funktion als Argument aufnehmen, anstatt ein Objekt, das so aussieht;

this.setState(function(state){ 
    ... 
    return newState 
}); 

Mit dieser Option können Sie auf den aktuellen Status (zum Zeitpunkt der Ausführung) über das übergebene Argument für diese Funktion zugreifen.