React setState non aggiorna lo stato


99

Quindi ho questo:

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 è solo un array di numeri, [1, 5, 9]ad es. tuttavia this.state.dealersOverallTotalnon fornisce il totale corretto ma lo totalfa? Ho anche inserito un ritardo di timeout per vedere se questo ha risolto il problema. ovvio o dovrei inserire più codice?



@Assan cheers !!
Il verme

Oltre a quanto viene detto nelle risposte, stai registrando esplicitamente il valore dello stato, prima di chiamare setState.
Felix Kling

1
@FelixKling no, chiamo this.state dopo averlo impostato. Sto registrando una variabile prima. no?
Il verme

A causa del timeout il tuo setStateviene effettivamente eseguito dopo aver registrato lo stato. Penso che quello che volevi fare nel debugging fosse mettere la console.logparte all'interno del timeout e setStateall'esterno.
Fabian Schultz

Risposte:


192

setState()di solito è asincrono, il che significa che al momento console.logdello stato non è ancora aggiornato. Prova a inserire il log nella richiamata del setState()metodo. Viene eseguito al termine del cambio di stato:

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 

2
Oltre a ciò, l'OP registra esplicitamente il valore dello stato prima di chiamare setState.
Felix Kling

Questo funziona anche per me, in passato ho usato questo: `this.setState ({someVar: newValue}, function () {console.log (" force update}); 'ma per qualche motivo non era preoccupante non più, quando ho aggiornato il codice come descritto sopra funziona. qualche idea del perché?
Jozcar

1
@Jozcar dovrebbe funzionare anche, la sintassi non era corretta (parentesi mancanti):this.setState({someVar: newValue},function(){ console.log("force update") });
Fabian Schultz

imgur.com/Ku0OjTl Per favore dimmi cosa devo fare per sbarazzarmi di questo problema.
Johncy

1
Avevo completamente dimenticato il fatto che si tratta di una chiamata asincrona e ho apportato tutte le possibili modifiche al codice tranne questa e qui hai salvato il mio cervello dal bruciarsi. grazie
Hem M

17

setState è asincrono. È possibile utilizzare il metodo di callback per ottenere lo stato aggiornato.

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

12

Utilizzo di async / await

async changeHandler(event) {
    await this.setState({ yourName: event.target.value });
    console.log(this.state.yourName);
}

8

L' setState()operazione è asincrona e quindi console.log()verrà eseguita prima che setState()i valori mutino e quindi vedrai il risultato.

Per risolverlo, registra il valore nella funzione di callback di setState(), come:

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)

JavaScript è sempre sincrono.
Santosh Singh

1
@santoshsingh hai un'idea sbagliata. Le chiamate API e i timeout avvengono tutti in modo asincrono.
Shubham Khatri

Come hai detto sopra, javascript è asincrono --- non è corretto. È principalmente sincrono e per i casi è asincrono. stackoverflow.com/questions/2035645/…
Santosh Singh

@santoshsingh. Ohh è stato un errore da parte mia. La frase non è stata
formata

uso molto intelligente della richiamata per garantire che lo stato venga aggiornato prima della chiamata successiva!
user1204214

7

In caso di hook, dovresti usare useEffecthook.

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

setFruit('Apple');

useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])

Ottimo, funziona con useEffect. Ma perché ne ha bisogno?
alex351

useEffectviene eseguito ad ogni nuovo rendering e se gli elementi passati nell'array sono variabili di stato sand cambiati. Quindi, quando il frutto cambia e il componente viene nuovamente renderizzato, useEffect verrà eseguito.
Siraj Alam

Eseguo setFruit e console.log fruit al di fuori di useEffect e non cambia. : /
alex351

4

Il setstate è asincrono nella reazione, quindi per vedere lo stato aggiornato nella console utilizzare il callback come mostrato di seguito (la funzione di callback verrà eseguita dopo l'aggiornamento setstate)

inserisci qui la descrizione dell'immagine

Il metodo seguente è "sconsigliato" ma per la comprensione, se si modifica lo stato direttamente è possibile vedere lo stato aggiornato nella riga successiva. Ripeto questo è "sconsigliato"

inserisci qui la descrizione dell'immagine


GRAZIE questo è tutto, devi impostare direttamente la variabile
notacorn


1

Ho avuto la stessa situazione con un codice contorto e niente dei suggerimenti esistenti ha funzionato per me.

Il mio problema era che setStatestava accadendo dalla funzione di callback, emessa da uno dei componenti. E il mio sospetto è che la chiamata avvenisse in modo sincrono, il che ha impedito setStatedel tutto l'impostazione dello stato.

In poche parole, ho qualcosa del genere:

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

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

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

Il modo in cui dovevo "aggiustarlo" era mettere doUpdate() in setTimeoutquesto modo:

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

Non è l'ideale, ma altrimenti sarebbe un refactoring significativo.


Questo ha risolto il mio problema, ma ho invece inserito setState () all'interno di setTimeout (). Grazie!
thargenediad

0

Ho riscontrato un problema durante l'impostazione dello stato di reazione più volte (utilizzava sempre lo stato predefinito). A seguito di questo problema di react / github ha funzionato per me

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

// Do this!
setState(prevState => {
  return {
    ...prevState,
    foo: "def"
  };
});
setState(prevState => {
  return {
    ...prevState,
    bar: 456
  };
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.