React setState não atualizando estado

99

Então, eu tenho isso:

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 é apenas uma matriz de números, [1, 5, 9]por exemplo this.state.dealersOverallTotal, não fornece o total correto, mas totalfornece? Até coloquei um tempo limite para ver se isso resolveu o problema. algum óbvio ou devo postar mais código?

O verme
fonte
@Assan cheers !!
O worm de
Além do que é dito nas respostas, você está registrando explicitamente o valor do estado, antes de ligar setState.
Felix Kling
1
@FelixKling não, estou chamando this.state depois de defini-lo. Estou registrando uma variável antes. não?
O worm
Por causa do tempo limite, seu setStateé realmente executado após registrar o estado. Acho que o que você pretendia fazer na depuração era colocar a console.logparte dentro do tempo limite e setStatefora dela.
Fabian Schultz

Respostas:

192

setState()geralmente é assíncrono, o que significa que no momento em que você console.logo estado, ele ainda não está atualizado. Tente colocar o log no retorno de chamada do setState()método. É executado após a conclusão da mudança de estado:

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 
Fabian Schultz
fonte
2
Além disso, o OP registra explicitamente o valor do estado antes de chamar setState.
Felix Kling
Isso funciona para mim também, no passado eu usei este: `this.setState ({someVar: newValue}, function () {console.log (" force update}); 'mas por algum motivo não era preocupante mais, quando eu atualizei o código conforme descrito acima, ele funcionou. alguma ideia por quê?
Jozcar
1
@Jozcar também deve funcionar, a sintaxe não estava certa (parênteses faltando):this.setState({someVar: newValue},function(){ console.log("force update") });
Fabian Schultz
imgur.com/Ku0OjTl Diga-me o que devo fazer para me livrar deste problema.
Johncy 01 de
1
Eu tinha esquecido completamente o fato de que é uma chamada assíncrona e fiz todas as alterações de código possíveis, exceto esta, e aqui você salvou meu cérebro de queimar. obrigado
Hem M
17

setState é assíncrono. Você pode usar o método de retorno de chamada para obter o estado atualizado.

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

Usando async / await

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

A setState()operação é assíncrona e, portanto, você console.log()será executado antes de setState()alterar os valores e, portanto, você verá o resultado.

Para resolver isso, registre o valor na função de retorno de chamada de setState(), como:

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)
Shubham Khatri
fonte
JavaScript é sempre síncrono.
Santosh Singh
1
@santoshsingh você tem um conceito errado. Chamadas de API e tempos limite acontecem de forma assíncrona.
Shubham Khatri
Como você mencionou acima, o javascript é assíncrono --- não está correto. É principalmente síncrono e para os casos é assíncrono. stackoverflow.com/questions/2035645/…
Santosh Singh
@santoshsingh. Ohh isso foi um erro da minha parte. Não formou a frase corretamente
Shubham Khatri
uso muito inteligente do retorno de chamada para garantir que o estado seja atualizado antes da chamada subsequente!
user1204214
7

No caso de ganchos, você deve usar useEffectgancho.

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

setFruit('Apple');

useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])
Siraj Alam
fonte
Ótimo, funciona com useEffect. Mas por que precisa de um?
alex351
useEffecté executado em cada re-renderização, e se os itens passados ​​na matriz são variáveis ​​de estado e mudados. Portanto, quando a fruta for alterada e o componente for renderizado novamente, esse useEffect será executado.
Siraj Alam
Eu executo setFruit e console.log fruit fora de useEffect e isso não muda. : /
alex351
4

O setstate é assíncrono na reação, portanto, para ver o estado atualizado no console, use o retorno de chamada conforme mostrado abaixo (a função de retorno de chamada será executada após a atualização do setstate)

insira a descrição da imagem aqui

O método abaixo "não é recomendado", mas para compreensão, se você alterar o estado diretamente, poderá ver o estado atualizado na próxima linha. Repito que isso é "não recomendado"

insira a descrição da imagem aqui

Mokesh S
fonte
OBRIGADO é isso, você deve definir diretamente a variável
notacorn
1

Eu tive a mesma situação com alguns códigos complicados e nada das sugestões existentes funcionou para mim.

Meu problema era que setStateestava acontecendo a partir da função callback, emitida por um dos componentes. E minha suspeita é que a chamada estava ocorrendo de forma síncrona, o que impedia setStatede configurar o estado de forma alguma.

Simplificando, eu tenho algo assim:

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

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

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

A maneira que eu tinha de "correção" que era para colocar doUpdate()em setTimeoutcomo este:

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

Não é o ideal, mas de outra forma seria uma refatoração significativa.

zmecânico
fonte
Isso resolveu meu problema, mas coloquei setState () dentro de setTimeout (). Obrigado!
thargenediad
0

Tive um problema ao definir o estado de reação várias vezes (sempre usava o estado padrão). Seguir este problema de reação / github funcionou para mim

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

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