Tengo dos api que debería convertirlas en una matriz así
[ { key: "0", label: 'Installation', children: [ { key: "0-0", label: 'Getting Started', url: 'https://reactjs.org/docs/getting-started.html' }, { key: "0-1", label: 'Add React', url: 'https://reactjs.org/docs/add-react-to-a-website.html' }, { key: "0-2", label: 'Create an App', url: 'https://reactjs.org/docs/create-a-new-react-app.html' }, { key: "0-3", label: 'CDN Links', url: 'https://reactjs.org/docs/cdn-links.html' } ] }, { key: "1", label: 'Main Concepts', children: [ { key: "1-0", label: 'Hello World', url: 'https://reactjs.org/docs/hello-world.html' }, { key: "1-1", label: 'Introducing JSX', url: 'https://reactjs.org/docs/introducing-jsx.html' }, { key: "1-2", label: 'Rendering Elements', url: 'https://reactjs.org/docs/rendering-elements.html' }, { key: "1-3", label: 'Components and Props', url: 'https://reactjs.org/docs/components-and-props.html' }, { key: "1-4", label: 'State and LifeCycle', url: 'https://reactjs.org/docs/state-and-lifecycle.html' }, { key: "1-5", label: 'Handling Events', url: 'https://reactjs.org/docs/handling-events.html' } ] } ];Por cierto, tengo dos API, una de ellas obtiene todas las categorías, la segunda API es para tomar los nombres de los niños. Así que creé una búsqueda encadenada, pero no puedo tomar el objeto de los niños correctamente. children array convierte a that 'children: Promise {: Array(11)}' ¿Qué significa cumplido aquí? porque mi código no funciona por ese motivo. Quiero compartir mi código también
getCategories() { return fetch('https://challenge.fnaghshin.com/api/cat') .then((res) => res.json()) .then((d) => { return Promise.all( d.map((e) => { return { key: e.id, label: e.name, date: e.created_at, children: fetch( `https://challenge.fnaghshin.com/api/catpro/${e.id}` ) .then((res) => res.json()) .then((d) => d.map((e) => { return { key: e.id, label: e.name, }; }) ), }; }) ); }); }También usé Promise.all() para esperar a que se cumplieran todas las promesas en lugar de convertirme en la matriz correcta. Pero fallé
En mi opinión, la solución más limpia es usar async/await, con Promises anidadas rápidamente se vuelve bastante ilegible.
async function getCategories() { const response = await fetch("https://challenge.fnaghshin.com/api/cat"); const categories = await response.json(); const childrenResponses = await Promise.all( categories.map((cat) => fetch(`https://challenge.fnaghshin.com/api/catpro/${cat.id}`) ) ); const childrenData = await Promise.all( childrenResponses.map((response) => response.json()) ); return categories.map((cat, index) => ({ key: cat.id, label: cat.name, date: cat.created_at, children: childrenData[index].map((child) => ({ key: child.id, label: child.title })) })); } Así que primero obtienes tus categorías, eso es bastante simple. Entonces, lo que quiere hacer es usar Promise.all() en la lista de llamadas de búsqueda con ID que tiene de categorías (respuestas de childrenResponses ). Luego, debe hacer lo mismo debido a .json() en fetch (sería aún más limpio con, por ejemplo axios o una biblioteca de nivel superior similar en lugar de fetch ), y una vez que tenga categorías y datos de niños, solo tiene que mapearlo de la manera que desear. Puede hacerlo un poco más conciso haciendo, por ejemplo, esto en su lugar:
const categories = await fetch( "https://challenge.fnaghshin.com/api/cat" ).then((res) => res.json());aunque en mi opinión es menos legible. Probablemente también debería hacer algún manejo de errores, por ejemplo, con try/catch.
Aquí hay una versión basada en promesas. Dividí la función principal en partes, para que sea más fácil de leer.
Tenga en cuenta que debido a que está realizando muchas solicitudes a la API, es probable que reciba un 429: too many requests de advertencia.
Para resolver eso, puede usar proxies para cada solicitud, o puede verificar el código de estado y esperar el tiempo que la respuesta le indica que espere.
const URL = 'https://challenge.fnaghshin.com/api/cat'; const CHILDREN_URL = `https://challenge.fnaghshin.com/api/catpro/`; function getCategories() { return fetch(URL) .then(res => res.json()) .then(data => Promise.all(data.map(getSubCategories))); } function getSubCategories(data) { return fetch(CHILDREN_URL + data.id) .then(res => res.json()) .then(info => ({ key: data.id, label: data.name, date: data.created_at, children: info.map(e => ({ key: e.id, label: e.title, })), })); } getCategories() .then(console.log) .catch(console.log)Promise.all() espera una serie de promesas, pero estaba devolviendo una serie de objetos. La promesa estaba anidada en el elemento secundario de children objetos. Entonces, lo que debemos hacer es trazar un mapa sobre estos objetos y devolver los elementos secundarios anidados y alimentar eso a children Promise.all()
Agregué una función asíncrona al segundo bloque, por then que puedo usar await con Promise.all() . Eso hace que la ejecución del código espere hasta que todas las promesas, es decir, todos los children , se hayan resuelto. Después de eso, simplemente puedo devolver el resultado.
function getCategories() { return fetch('https://challenge.fnaghshin.com/api/cat') .then((res) => res.json()) .then(async (d) => { const withChildren = d.map((e) => { return { key: e.id, label: e.name, date: e.created_at, children: fetch(`https://challenge.fnaghshin.com/api/catpro/${e.id}`).then(res => res.json()) } }) await Promise.all(withChildren.map(item => item.children)) return withChildren }) } El 429 (Too Many Requests) parece ser un límite de velocidad, cuando activa las solicitudes con demasiada frecuencia dentro de un tiempo determinado. Yo también lo tenía. Ahora se ha ido de nuevo.
PD: No use await in map() en este caso, ya que esto hace que la ejecución dure más. Porque en cada iteración del mapa, await la respuesta de fetch() , antes de pasar a la siguiente iteración y disparar la siguiente fetch() . Entonces, en lugar de dispararlos todos a la vez (básicamente), los dispara uno tras otro hasta que se haya resuelto. Es más rápido dispararlos todos a la vez y luego esperar Promise.all() .