Я хочу получить данные для каждого объекта в массиве, переданном как реквизит (rootComments), и добавить данные в свойства объекта:
useEffect(() => {
rootComments.map(rootComment => {
if (rootComment.kids) {
rootComment.kidsText = []
fetchKidsText(rootComment.kids)
}
})
console.info(rootComments)
rootComments.map(comment => console.info(Object.values(comment)))
}, [rootComments])
const fetchKidsText = async (ids) => {
await Promise.all(
ids.map(id => fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`).then(response => response.json()).then(result => {
rootComments.map(comment => {
if (comment.id === result.parent) {
comment.kidsText = comment.kidsText.concat(result.text)
}
})
}))
);
}
Похоже, это не работает, я не могу отобразить rootComments.map(comment => comment.kidsText) и не могу зарегистрировать его как rootComments.map(comment => console.info(Object.values(comment))) (действует так, как будто нет нового свойства kidsText) или как rootComments.map(comment => console.info(comment.kidsText)) (возвращает пустой массив).
Но. Когда я регистрируюсь console.info(rootComments), он возвращает массив объектов с новым свойством kidsText.
Моя первая мысль заключалась в том, что useEffect() не ждет, пока rootComments будет извлечен внутри другого компонента, но это не кажется проблемой, так что, может быть, это что-то внутри fetchKidsText() или то, как он взаимодействует с useEffect()?





Несколько вещей неверны в этом коде:
rootComments без использования setState (реакция не может обновляться с него)map для итерации, но отбрасываете результат.then в функции async / awaitPromise.all, а вместо этого await его.map не является циклом for, используйте либо .forEach, либо цикл for..of
Что касается вашего фактического вопроса, мой первый вопрос, вероятно, является основной проблемой, покажите больше кода, чтобы мы могли подтвердить
отредактируйте предложенный альтернативный код:
useEffect(() => {
// get all the kids id, this create a single big array with every kids:
const allKids = rootComments.flatMap(rootComment => rootComment.kids || [])
// use a controller too cancel fetch request if component is unmounted
// otherwhise, trying to setState if the component is unmounted will
// mess react up:
const controller = new AbortController()
// we fetch all the kids at once instead of doing this in a map like before
fetchKidsText(allKids, controller.signal)
.then(setRootComment) // note that i'm using `.then` here,
// because we can't await in hooks we must return a callback or undefined.
.catch(err => {
if (err.name === 'AbortError') return // we can safely ignore abort error
// ? handle error here
})
return () => controller.abort()
}, [rootComments])
const fetchKidsText = async (ids, signal) => {
// first we call the api and get everything a big result
const results = await Promise.all(ids.map(async id => {
const url = `https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`
const res = await fetch(url, { signal })
return res.json()
}))
// now what you were trying to do was merge every children text comment
// since we got them all, just one filter should work:
return rootComments.map(comment => {
const children = results.filter(r => r.parent === comment.id)
const kidsText = children.map(r => r.text)
return { ...comments, kidsText }
})
}
Не используйте этот код как есть, я не проверял его, просто чтобы объяснить, как я попытался бы решить вашу проблему с комментариями, чтобы объяснить свое мнение.
Удачи !
В вашем коде много чего не так. Я думаю, что текущий ответ @kigiri довольно хорошо резюмирует эти проблемы.