const [counter, setCounter] = useState(0)Digamos que tengo dos funciones asíncronas func1 y func2. Ambas funciones son asíncronas y actualizan el estado del contador. func1 se ejecuta antes que func2.
async function func1() { ....extra code setCounter(counter + 1) } async function func2() { ....extra code setCounter(counter + 1) } func1() func2()Preguntas:
Aquí, tanto el estado de uso de func1 como el de func2 hacen el mismo trabajo de incrementar Counter en 1. No importa qué función se ejecute primero, el resultado será el mismo. Pero mientras responde, responda como si ambos estados hicieran las diferentes tareas y para lograr el resultado deseado, func1 debería ejecutarse antes que func2.
¿Está garantizado que cuando
func2deuseState,func1actualiza el estado del contador?
No, en absoluto.
De lo contrario, ¿qué debo hacer para asegurarme de que el estado de uso de
func2se ejecute solo después de que el estado deUsestatefunc1actualizado el valor del contador?
Puede hacer que func2 espere hasta que se establezca la promesa devuelta por func1 (las funciones async siempre devuelven una promesa), pero eso no necesariamente significa que func2 no comenzó a ejecutarse antes de que ocurriera la actualización de estado de setCounter ; las actualizaciones de estado también son asíncronas.
Para estar seguro de eso, debe esperar a que se establezca la promesa de func1 y usar el formulario de devolución de llamada de setCounter : setCounter(c => c + 1) :
async function func1() { // ....extra code setCounter(counter + 1); } async function func2() { // ....extra code setCounter(c => c + 1); // Note the callback form of state setter } func1().then(() => func2); Hay una docena de maneras de girar eso. Por ejemplo, podría pasar la promesa de func1 a func2 como un argumento y hacer que solo lo await al final:
La idea básica es hacer que func2 espere hasta que func1 .
async function func1() { // ....extra code setCounter(counter + 1); } async function func2(promise) { // ....extra code await promise; // Wait for `func1` to finish setCounter(c => c + 1); // Note the callback form of state setter } func2(func1()); En la gran mayoría de los casos, probablemente no le importe si func1 está hecho o no; simplemente use el formulario de devolución de llamada de setCounter en ambos lugares para que ninguno de ellos use el estado obsoleto (el counter que cierran):
async function func1() { // ....extra code setCounter(c => c + 1); } async function func2() { // ....extra code setCounter(c => c + 1); } func1(); func2(); De hecho, diría que cada vez que usa el estado existente (valor anterior del counter ) para actualizar el estado (incrementándolo en uno), debe usar el formulario de devolución de llamada del setter. Es realmente fácil cerrar una copia obsoleta de la variable de estado; usar el formulario de devolución de llamada asegura que está usando un estado actualizado.
No, definitivamente no está garantizado que cuando se ejecuta func2 , func1 ya haya actualizado el estado. Lo que puede hacer para lograr eso con un componente funcional es usar el gancho useEffect para rastrear los cambios en el contador de estado:
useEffect(() => { func2(); }, [counter])Al hacer esto, está ejecutando func2 cada vez que cambia el estado del contador. Además, si desea asegurarse de que func2 se ejecute solo una vez después de que func1 actualice el estado, puede usar una bandera como esta:
const isStateUpdatedByFunc1 = useRef(false); async function func1() { ....extra code isStateUpdatedByFunc1.current = true; setCounter(counter + 1); } useEffect(() => { if(isStateUpdatedByFunc1.current){ isStateUpdatedByFunc1.current = false; func2(); } }, [counter])