Reagieren Sie darauf, dass setState den Status nicht aktualisiert

91

Also ich habe folgendes:

let total = newDealersDeckTotal.reduce(function(a, b) {
  return a + b;
},
0);

console.log(total, 'tittal'); //outputs correct total
setTimeout(() => {
  this.setState({dealersOverallTotal: total});
}, 10);

console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1'); //outputs incorrect total

newDealersDeckTotal ist nur ein Array von Zahlen, [1, 5, 9]z. B. this.state.dealersOverallTotalgibt es nicht die richtige Summe, totalaber? Ich habe sogar eine Zeitüberschreitung verzögert, um zu sehen, ob dies das Problem gelöst hat. irgendwelche offensichtlichen oder sollte ich mehr Code posten?

Der Wurm
quelle
@ Assan Prost !!
Der Wurm
Neben dem, was in den Antworten gesagt wird, protokollieren Sie explizit den Wert des Status, bevor Sie anrufen setState.
Felix Kling
1
@FelixKling nein ich rufe this.state auf, nachdem ich es eingestellt habe. Ich protokolliere vorher eine Variable. Nein?
Der Wurm
Aufgrund des Timeouts wird Ihr Programm setStatetatsächlich ausgeführt, nachdem Sie den Status protokolliert haben. Ich denke, was Sie beim Debuggen tun wollten, war, den console.logTeil innerhalb und setStateaußerhalb des Timeouts zu platzieren .
Fabian Schultz

Antworten:

180

setState()ist normalerweise asynchron, was bedeutet, dass es zum Zeitpunkt console.logdes Status noch nicht aktualisiert ist. Versuchen Sie, das Protokoll in den Rückruf der setState()Methode einzufügen . Es wird ausgeführt, nachdem die Statusänderung abgeschlossen ist:

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 
Fabian Schultz
quelle
1
Darüber hinaus protokolliert das OP den Statuswert explizit, bevor sie aufgerufen werden setState.
Felix Kling
Dies funktioniert auch für mich. In der Vergangenheit habe ich Folgendes verwendet: `this.setState ({someVar: newValue}, function () {console.log (" Update erzwingen}); ', aber aus irgendeinem Grund war es nicht besorgniserregend mehr, wenn ich den Code wie oben beschrieben aktualisiert habe, funktioniert es.
Irgendeine
@Jozcar Sollte auch funktionieren, war die Syntax nicht richtig (fehlende Klammern):this.setState({someVar: newValue},function(){ console.log("force update") });
Fabian Schultz
imgur.com/Ku0OjTl Bitte sagen Sie mir, was ich tun soll, um dieses Problem zu beseitigen.
Johncy
Dies funktioniert nicht, wenn Sie useStateHook in einer Funktionskomponente verwenden. Verwenden Sie useEffectstattdessen für einen Effekt nach dem Rendern.
Hasan Sefa Ozalp
16

setState ist asynchron. Sie können die Rückrufmethode verwenden, um den aktualisierten Status abzurufen.

changeHandler(event) {
    this.setState({ yourName: event.target.value }, () => 
    console.log(this.state.yourName));
 }
Mahesh Joshi
quelle
10

Verwenden von async / await

async changeHandler(event) {
    await this.setState({ yourName: event.target.value });
    console.log(this.state.yourName);
}
Dev01
quelle
Ich mache das gleiche. Arbeitete für mich
Prodeveloper
8

Die setState()Operation ist asynchron und daher wird Ihr Vorgang console.log()ausgeführt, bevor setState()die Werte mutiert werden und Sie das Ergebnis sehen.

Um dies zu lösen, protokollieren Sie den Wert in der Rückruffunktion von setState():

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)
Shubham Khatri
quelle
JavaScript ist immer synchron.
Santosh Singh
1
@ Santoshsingh Sie haben ein Missverständnis. API-Aufrufe und Timeouts erfolgen alle asynchron.
Shubham Khatri
Wie Sie oben erwähnt haben, ist Javascript asynchron - es ist nicht korrekt. Es ist hauptsächlich synchron und in einigen Fällen asynchron. stackoverflow.com/questions/2035645/…
Santosh Singh
@ Santoshsingh. Ohh das war ein Fehler von meiner Seite. Hat den Satz nicht richtig gebildet
Shubham Khatri
Sehr geschickte Verwendung des Rückrufs, um sicherzustellen, dass der Status vor dem nachfolgenden Aufruf aktualisiert wird!
user1204214
5

Bei Haken sollten Sie einen useEffectHaken verwenden.

const [fruit, setFruit] = useState('');

setFruit('Apple');

useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])
Siraj Alam
quelle
Großartig, es funktioniert mit useEffect. Aber warum braucht es einen?
alex351
useEffectwird bei jedem erneuten Rendern ausgeführt, und wenn die an das Array übergebenen Elemente Zustandsvariablen sind, wird Sand geändert. Wenn sich die Frucht ändert und die Komponente neu gerendert wird, wird useEffect ausgeführt.
Siraj Alam
Ich führe setFruit und console.logruit außerhalb von useEffect aus und es ändert sich nicht. : /
alex351
3

Der Setstate reagiert asynchron. Um den aktualisierten Status in der Konsole anzuzeigen, verwenden Sie den folgenden Rückruf (die Rückruffunktion wird nach dem Setstate-Update ausgeführt.)

Geben Sie hier die Bildbeschreibung ein

Die folgende Methode wird "nicht empfohlen", aber zum besseren Verständnis können Sie den aktualisierten Status in der nächsten Zeile sehen, wenn Sie den Status direkt mutieren. Ich wiederhole dies ist "nicht zu empfehlen"

Geben Sie hier die Bildbeschreibung ein

Mokesh Moha
quelle
DANKE das ist es, du musst die Variable direkt einstellen
notacorn
0

Ich hatte ein Problem beim mehrmaligen Einstellen des Reaktionsstatus (es wurde immer der Standardstatus verwendet). Nach diesem React / Github- Problem hat es bei mir funktioniert

const [state, setState] = useState({
  foo: "abc",
  bar: 123
});

// Do this!
setState(prevState => {
  return {
    ...prevState,
    foo: "def"
  };
});
setState(prevState => {
  return {
    ...prevState,
    bar: 456
  };
});
Arun Gopalpuri
quelle
0

Ich hatte die gleiche Situation mit einem verschlungenen Code, und nichts von den vorhandenen Vorschlägen hat für mich funktioniert.

Mein Problem war, dass setStatedies von einer von einer der Komponenten ausgegebenen Rückruffunktion geschah. Und mein Verdacht ist, dass der Anruf synchron erfolgte, was dies verhindertesetState Setzen des Status überhaupt verhinderte.

Einfach gesagt, ich habe so etwas:

render() {
    <Control
        ref={_ => this.control = _}
        onChange={this.handleChange}
        onUpdated={this.handleUpdate} />
}

handleChange() {
    this.control.doUpdate();
}

handleUpdate() {
    this.setState({...});
}

Die Art , wie ich zu „reparieren“ hatte es setzt doUpdate()in setTimeoutetwa so aus :

handleChange() {
    setTimeout(() => { this.control.doUpdate(); }, 10);
}

Nicht ideal, aber sonst wäre es ein bedeutendes Refactoring.

zmechanic
quelle