Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

209
Vistas
¿Por qué esta receta de prueba oficial de React usando await/act/async realmente funciona?

He estado trabajando con Javascript durante un par de años y, con mi conocimiento actual del bucle de eventos, me cuesta entender por qué funciona esta receta de prueba de los documentos de React. ¿Alguien podría desglosar exactamente lo que sucede en cada paso allí? A mi me parece mágico que esto funcione en la prueba:

 await act(async () => { render(<User id="123" />, container); }); // expect something

El componente se ve así (copiando en caso de que el enlace quede obsoleto):

 function User(props) { const [user, setUser] = useState(null); async function fetchUserData(id) { const response = await fetch("/" + id); setUser(await response.json()); } useEffect(() => { fetchUserData(props.id); }, [props.id]); if (!user) { return "loading..."; } return ( <details> <summary>{user.name}</summary> <strong>{user.age}</strong> years old <br /> lives in {user.address} </details> ); }

No hay un retorno implícito o explícito en el renderizado, entonces, ¿cómo sabe Act para esperar las cosas asíncronas que suceden en el componente (obtención, etc.)?

Para mí, esto tendría más sentido:

 await act(async () => render(<User id="123" />, container));

o (que es lo mismo):

 await act(async () => { return render(<User id="123" />, container); });

o incluso:

 await act(render(<User id="123" />, container));

Pero no parece ser así como la gente lo usa, o cómo se pretendía que se usara, así que estoy un poco perdido. He visto los mismos ejemplos con mount de enzimas.

No quiero crear una prueba frágil, así que realmente quiero entender esto.

¿Tiene algo que ver con que la devolución de llamada sea asíncrona, es decir, agrega algo al ciclo de eventos al final, de modo que la espera espera a que suceda todo dentro del procesamiento antes de resolverse?

Me estoy quedando en blanco aquí y estoy luchando en la jungla de reacción doc, porque todo el mundo parece usar este patrón, pero nadie explica realmente por qué o cómo funciona.

¡Gracias por la ayuda por adelantado!

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

Al mirar más de cerca el código fuente de react-dom y react-dom/test-utils , parece que lo que hace que todo esto funcione es esta llamada setImmediate que ocurre después del primer efecto de descarga en recursivelyFlushAsyncActWork .

Parece que act elige usar este FlushAsyncActWork de forma recursivelyFlushAsyncActWork simplemente porque la devolución de llamada tiene la firma de ser "entonces posible", es decir, una Promesa. Puedes ver esto aquí .

Esto debería significar que lo que sucede es (simplificado) esto:

  1. La devolución de llamada useEffect se vacía (poniendo fetch en el bucle de eventos).
  2. La devolución de llamada setImmediate "garantiza" que se resuelva nuestra promesa / recuperación simulada.
  3. Una tercera descarga ocurre por una recursión dentro de la devolución de llamada setImmediate (llamada por enqueueTask ) que hace que los cambios de estado aparezcan en el DOM.
  4. Cuando no queda nada para tirar, llama a la resolve más externa y nuestro act se resuelve.

En el código que se parece a esto (excepto que se tomó de una versión anterior de react-dom de node_modules de mi proyecto React, hoy en día flushWorkAndMicroTasks parece llamarse recursivelyFlushAsyncActWork ):

 function flushWorkAndMicroTasks(resolve) { try { flushWork(); // <- First effect flush (fetch will be invoked by the useEffect?) enqueueTask(function () { // <- setImmediate is called in here (finishes the fetch) if (flushWork()) { // <- Flush one more time and the next loop this will be false flushWorkAndMicroTasks(resolve); } else { resolve(); // <- resolve is called when flushWork has nothing left to flush. } }); } catch (err) { resolve(err); } }

Información adicional (actualización)

A menos que me equivoque, esto debería significar que await act(async () => { render(...); }); "solo" espera un ciclo de eventos a menos que se agregue una nueva tarea con el último vaciado. Es decir, es posible agregar promesas de forma recursiva si hay un vaciado en el medio, también las micro tareas, como las cadenas de promesas, probablemente se resolverán durante el primer ciclo (ya que técnicamente están "bloqueando" ( fuente )).

Eso significa que si agrega un temporizador o algo más en su código simulado o React que, naturalmente, podría necesitar múltiples bucles para resolverse, no se esperará porque el evento "después" no se captura antes de resolverse, ya que los oyentes no están conectados / volvió a la promesa externa (¡corríjame si me equivoco!).

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda