it-swarm.com.de

SetState kann nicht sofort aktualisiert werden

Ich arbeite an einer ToDo-Anwendung. Dies ist eine sehr vereinfachte Version des fehlerhaften Codes. Ich habe eine Checkbox:

 <p><input type="checkbox"  name="area" checked={this.state.Pencil}   onChange={this.checkPencil}/> Writing Item </p>

Hier ist die Funktion, die das Kontrollkästchen aufruft:

checkPencil(){
   this.setState({
      pencil:!this.state.pencil,
  }); 
  this.props.updateItem(this.state);
}

updateItem ist eine Funktion, die dem Versand an redux zugeordnet ist

function mapDispatchToProps(dispatch){
  return bindActionCreators({ updateItem}, dispatch);
}

Mein Problem ist, dass wenn ich die updateItem-Aktion und console.log den Status aufrufe, immer ein Schritt hinterher ist. Wenn das Kontrollkästchen nicht markiert ist und nicht "true" ist, wird der Status "true" weiterhin an die updateItem-Funktion übergeben. Muss ich eine andere Funktion aufrufen, um die Aktualisierung des Status zu erzwingen? 

40
lost9123193

Sie sollten Ihre zweite Funktion als Rückruf für setState aufrufen, da setState asynchron erfolgt. So etwas wie:

this.setState({pencil:!this.state.pencil}, myFunction)

In Ihrem Fall jedoch, da diese Funktion mit einem Parameter aufgerufen werden soll, müssen Sie etwas kreativer werden und möglicherweise eine eigene Funktion erstellen, die die Funktion in den Requisiten aufruft:

myFunction = () => {
  this.props.updateItem(this.state)
}

Kombinieren Sie diese und es sollte funktionieren.

67
Ben Hare

Der Aufruf von setState() in React ist aus verschiedenen Gründen (hauptsächlich Leistung) asynchron. Unter den Deckeln wird React mehrere Aufrufe von setState() in eine Mutation mit einem einzelnen Status stapeln und die Komponente dann ein einziges Mal erneut rendern, anstatt für jede Statusänderung ein neues Rendering durchzuführen.

Glücklicherweise ist die Lösung ziemlich einfach - setState akzeptiert einen Rückrufparameter:

checkPencil(){
   this.setState({
      pencil:!this.state.pencil,
  }, function () {
      this.props.updateItem(this.state);
  }.bind(this));
}
13
rossipedia

Wenn Sie Ihren Status mit einer Eigenschaft des aktuellen Status aktualisieren, empfehlen Sie in der React-Dokumentation, die Funktionsaufrufversion von setState anstelle des Objekts zu verwenden.

Also setState((state, props) => {...}) anstelle von setState(object).

Der Grund ist, dass setState eher eine Anforderung für den Status ist als eine sofortige Änderung. Reagieren Sie Batches, die setState zur Leistungsverbesserung aufruft. 

Dies bedeutet, dass die Zustandseigenschaft, die Sie prüfen, möglicherweise nicht stabil ist.

Weitere Informationen finden Sie in der Dokumentation hier: https://facebook.github.io/react/docs/react-component.html#setstate


Um Ihre Frage zu beantworten, würde ich das tun. 

checkPencil(){
    this.setState((prevState) => {
        return {
            pencil: !prevState.pencil
        };
    }, () => {
        this.props.updateItem(this.state)
    });
}
9
GBL

Es liegt daran, dass es asynchron passiert, dh, dass in dieser Zeit möglicherweise noch nicht aktualisiert wird ...

Gemäß der Dokumentation zu React V.16 müssen Sie eine zweite Form von setState() verwenden, die eine Funktion und kein Objekt akzeptiert:

Statusaktualisierungen können asynchron sein

React kann mehrere setState () - Aufrufe in ein einzelnes Update für .__ einschließen. Performance.

Da this.props und this.state asynchron aktualisiert werden können, müssen Sie sollte sich bei der Berechnung des nächsten Zustands nicht auf ihre Werte verlassen.

Beispielsweise kann dieser Code den Zähler möglicherweise nicht aktualisieren:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

Um dies zu beheben, verwenden Sie eine zweite Form von setState (), die eine Funktion .__ akzeptiert. eher als ein Objekt. Diese Funktion erhält den vorherigen Zustand als erstes Argument und die Requisiten zum Zeitpunkt der Aktualisierung als zweites Argument:

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));
8
Alireza

Ben hat eine großartige Antwort darauf, wie das unmittelbare Problem gelöst werden kann. Ich würde jedoch auch raten, Doppelzustände zu vermeiden 

Wenn ein Status in redux ist, sollte Ihr Ankreuzfeld seinen eigenen Status aus einem Requisite oder Store lesen, anstatt den Überprüfungsstatus in seiner eigenen Komponente und im globalen Store zu verfolgen

Tun Sie so etwas:

<p>
    <input
        type="checkbox"
        name="area" checked={this.props.isChecked}
        onChange={this.props.onChange}
    />
    Writing Item
</p>

Wenn Sie feststellen, dass ein Zustand an mehreren Stellen benötigt wird, heben Sie ihn an einen gemeinsamen Elternteil (nicht immer redux), um nur eine einzige Wahrheit zu haben

2
CheapSteaks

versuche dies 

this.setState({inputvalue: e.target.value}, function () {
    console.log(this.state.inputvalue);
    this.showInputError(inputs[0].name);
}); 

showInputError-Funktion zur Überprüfung, wenn Formulare verwendet werden

2
Anish

Ich habe sowohl die Empfehlungen von rossipedia als auch von Ben Hare verwendet und Folgendes getan: 

checkPencil(){
   this.setState({
      pencil:!this.state.pencil,
   }, this.updatingItem); 
}

updatingItem(){
    this.props.updateItem(this.state)
}
2
lost9123193

Legen Sie zuerst Ihren Wert fest. Danach weiterarbeiten.

this.setState({inputvalue: e.target.value}, function () {
    this._handleSubmit();
}); 

_handleSubmit() {
   console.log(this.state.inputvalue);
   //Do your action
}
1
Kumaresan