Aquí está el problema: estoy tratando de llamar a 2 funciones con un clic de botón. Ambas funciones actualizan el estado (estoy usando el enlace useState). La primera función actualiza el valor1 correctamente a 'nuevo 1', pero después de 1s (setTimeout) se dispara la segunda función, y cambia el valor 2 a 'nuevo 2' ¡PERO! Establece el valor1 de nuevo a '1'. ¿Por qué está pasando esto? ¡Gracias por adelantado!
import React, { useState } from "react";
const Test = () => {
const [state, setState] = useState({
value1: "1",
value2: "2"
});
const changeValue1 = () => {
setState({ ...state, value1: "new 1" });
};
const changeValue2 = () => {
setState({ ...state, value2: "new 2" });
};
return (
<>
<button
onClick={() => {
changeValue1();
setTimeout(changeValue2, 1000);
}}
>
CHANGE BOTH
</button>
<h1>{state.value1}</h1>
<h1>{state.value2}</h1>
</>
);
};
export default Test;
javascript
reactjs
react-hooks
Bartek
fuente
fuente
changeValue2
?useState
usar o en su lugaruseReducer
.const [state, ...]
, y luego haciendo referencia a él en el setter ... Utilizará el mismo estado todo el tiempo.useState
llamadas separadas , una para cada "variable".Respuestas:
Bienvenido al infierno de cierre . Este problema ocurre porque cada vez que
setState
se llama,state
obtiene una nueva referencia de memoria, pero las funcioneschangeValue1
ychangeValue2
, debido al cierre, mantienen lastate
referencia inicial anterior .Una solución para garantizar la
setState
dechangeValue1
ychangeValue2
recupera el estado más reciente es el uso de una devolución de llamada (que tiene el estado anterior como un parámetro):Puede encontrar una discusión más amplia sobre este tema de cierre aquí y aquí .
fuente
Sus funciones deberían ser así:
Por lo tanto, se asegura de no perder ninguna propiedad existente en el estado actual utilizando el estado anterior cuando se activa la acción. También así evitas tener que gestionar cierres.
fuente
Cuando
changeValue2
se invoca, el estado inicial se mantiene para que el estado vuelva al estado inicial y luegovalue2
se escribe la propiedad.La próxima vez que
changeValue2
se invoca después de eso, mantiene el estado{value1: "1", value2: "new 2"}
, por lo quevalue1
se sobrescribe la propiedad.Necesita una función de flecha para el
setState
parámetro.fuente
Lo que pasa es que tanto
changeValue1
ychangeValue2
ver el estado del render que fueron creados en , por lo que cuando su componente rinde por primera vez estas 2 funciones, véase:Cuando hace clic en el botón,
changeValue1
se llama primero y cambia el estado a{value1: "new1", value2: "2"}
lo esperado.Ahora, después de 1 segundo,
changeValue2
se llama, pero esta función aún ve el estado inicial ({value1; "1", value2: "2"}
), por lo que cuando esta función actualiza el estado de esta manera:setState({ ...state, value2: "new 2" });
terminas viendo:
{value1; "1", value2: "new2"}
.fuente
fuente