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?



@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');
}); 

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));
 }

10

Usando async / await

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

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)

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])

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í


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
  };
});

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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.