React setState no actualiza el estado

91

Entonces tengo esto:

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 es solo una matriz de números, [1, 5, 9]por ejemplo, sin embargo this.state.dealersOverallTotal, no da el total correcto, pero total¿lo hace? Incluso puse un retraso de tiempo de espera para ver si esto resolvía el problema. ¿Algo obvio o debería publicar más código?

El gusano
fuente
@Assan salud !!
El gusano
Además de lo que se dice en las respuestas, está registrando explícitamente el valor del estado, antes de llamar setState.
Felix Kling
1
@FelixKling no, voy a llamar a this.state después de configurarlo. Estoy registrando una variable antes. ¿No?
El gusano
Debido al tiempo de espera, de setStatehecho, se ejecuta después de registrar el estado. Creo que lo que pretendías hacer al depurar era poner la console.logpieza dentro del tiempo de espera y setStatefuera.
Fabian Schultz

Respuestas:

181

setState()generalmente es asincrónico, lo que significa que en el momento en que console.logel estado, aún no está actualizado. Intente poner el registro en la devolución de llamada del setState()método. Se ejecuta después de que se completa el cambio de estado:

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 
Fabián Schultz
fuente
1
Además de eso, el OP registra explícitamente el valor del estado antes de llamar setState.
Felix Kling
Esto también funciona para mí, en el pasado he usado esto: `this.setState ({someVar: newValue}, function () {console.log (" force update}); 'pero por alguna razón no me preocupaba más, cuando actualicé el código como se describe arriba, funciona. ¿
Alguna
@Jozcar también debería funcionar, la sintaxis no era correcta (faltan paréntesis):this.setState({someVar: newValue},function(){ console.log("force update") });
Fabian Schultz
imgur.com/Ku0OjTl Por favor, dígame qué debo hacer para solucionar este problema.
Johncy
Esto no funciona si usa useStatehook en un componente funcional. Úselo en su useEffectlugar para un efecto después del renderizado.
Hasan Sefa Ozalp
16

setState es asincrónico. Puede utilizar el método de devolución de llamada para obtener el estado actualizado.

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

Usando async / await

async changeHandler(event) {
    await this.setState({ yourName: event.target.value });
    console.log(this.state.yourName);
}
Dev01
fuente
Estoy haciendo lo mismo. Trabajó para mí
prodeveloper
8

La setState()operación es asincrónica y, por lo tanto console.log(), se ejecutará antes de que setState()muta los valores y, por lo tanto, verá el resultado.

Para resolverlo, registre el valor en la función de devolución de llamada de setState(), como:

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)
Shubham Khatri
fuente
JavaScript siempre es sincrónico.
Santosh Singh
1
@santoshsingh, tienes un error. Las llamadas a la API y los tiempos de espera se producen de forma asincrónica.
Shubham Khatri
Como mencionaste anteriormente, JavaScript es asincrónico --- no es correcto. Es principalmente sincrónico y en algunos casos es asincrónico. stackoverflow.com/questions/2035645/…
Santosh Singh
@santoshsingh. Oh, eso fue un error de mi parte. No formó la oración correctamente
Shubham Khatri
uso muy inteligente de la devolución de llamada para garantizar que el estado se actualice antes de la siguiente llamada.
user1204214
5

En el caso de los anzuelos, debe utilizar el useEffectanzuelo.

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

setFruit('Apple');

useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])
Siraj Alam
fuente
Genial, funciona con useEffect. Pero, ¿por qué necesita uno?
alex351
useEffectse ejecuta en cada re-renderizado, y si los elementos pasados ​​a la matriz son variables de estado, arena cambia. Entonces, cuando la fruta cambia y el componente se vuelve a procesar, se ejecuta useEffect.
Siraj Alam
Ejecuto setFruit y console.log fruit fuera de useEffect, y no cambia. : /
alex351
3

El setstate es asíncrono en reacción, por lo que para ver el estado actualizado en la consola, use la devolución de llamada como se muestra a continuación (la función de devolución de llamada se ejecutará después de la actualización de setstate)

ingrese la descripción de la imagen aquí

El método siguiente "no se recomienda", pero para su comprensión, si modifica el estado directamente, puede ver el estado actualizado en la siguiente línea. Repito que esto es "no recomendado"

ingrese la descripción de la imagen aquí

mokesh moha
fuente
GRACIAS, esto es todo, tienes que establecer directamente la variable
notacorn
0

Tuve un problema al configurar el estado de reacción varias veces (siempre usaba el estado predeterminado). Seguir este problema de react / github funcionó para mí

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

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

Tuve la misma situación con un código complicado, y nada de las sugerencias existentes funcionó para mí.

Mi problema fue que setStateestaba sucediendo desde la función de devolución de llamada, emitida por uno de los componentes. Y mi sospecha es que la llamada se estaba produciendo de forma sincrónica, lo que impedía setStateestablecer el estado en absoluto.

En pocas palabras, tengo algo como esto:

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

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

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

La forma en que tenía que "arreglar" que era poner doUpdate()en setTimeouteste aspecto:

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

No es ideal, pero de lo contrario sería una refactorización significativa.

zmechanic
fuente