Estoy tratando de obtener episodios de forma incremental de una matriz, por lo que la experiencia del usuario se vería así:
Un usuario hace clic en un botón, muestra un indicador de carga, carga el primer episodio obtenido dentro de un div, pero sigue mostrando el indicador de carga debajo de ese primer episodio, continúa haciendo esto hasta que el mapa finaliza y se obtienen todos los episodios y el indicador de carga es ya no se muestra.
Pero aparentemente, esto no parece estar funcionando según lo planeado, sospecho que async-await no funciona como se esperaba dentro de un mapa.
Me pregunto si algo como rxjs ayudaría en este caso de uso (no tengo idea de cómo funciona, pero sé que se usa en los casos en que los datos se transmiten)
const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(''); const [data, setData] = useState([]); const handleClick = async () => { try { season.episodes.map(async (episode) => { setIsLoading(true); const links = await publicQueryClientApi( `${process.env.NEXT_PUBLIC_SERVER_URL}/download/${episode.slug}` ); setIsLoading(false); setData((prev) => [...prev, { episode, links }]); setError(''); }); } catch (error) { setIsLoading(false); setData([]); setError(error.message); } };La función async siempre devuelve una Promise .
Puedes intentar algo como esto:
const promises = season.episodes.map(async episode => { const links = await fetchLinks() // do other stuff return links }) const links = await Promise.all(promises) Y la otra cosa es que solo usa el map cuando desea una copia de la matriz pero modificada (usando una función que pasa al map que se ejecutará en cada elemento de la matriz). Por lo que puedo ver, su valor de retorno de la función de map no se guarda en ningún lado.
¿Por qué no simplemente usar la función recursiva, que buscará cada episodio y se llamará a sí mismo nuevamente para buscar otro mientras haya episodios "no buscados"? (No olvide marcar el episodio como "recuperado" cada vez, de lo contrario, hará un bucle infinito).
array.map no await su devolución de llamada, si es asíncrono. Entonces el resultado de
[...].map(async x => {}) es una matriz de promesas pendientes. Si desea agregar su episode uno por uno, debe usar un
try { for (let episode of season.episodes) { setIsLoading(true); const links = await publicQueryClientApi( `${process.env.NEXT_PUBLIC_SERVER_URL}/download/${episode.slug}` ); setIsLoading(false); setData((prev) => [...prev, { episode, links }]); setError(''); } } catch (e) { ... } Como su código ya está dentro de una función async , esto debería funcionar sin más modificaciones.
Otra posibilidad es usar Promise.all() , esto se resolverá una vez que se resuelvan todas las promesas en la matriz y devolverá sus resultados en una matriz.
try { setIsLoading(true); let allLinks = await Promise.all(season.episodes.map(e => { return publicQueryClientApi(...); }); setIsLoading(false); setData(season.episodes.map((e,i) => ({ episode: e, links: alllinks[i] })); setError(''); } catch (e) { ... }