I want to fetch data for every object in array passed as props (rootComments) and add the data to object properties:
useEffect(() => {
rootComments.map(rootComment => {
if (rootComment.kids) {
rootComment.kidsText = []
fetchKidsText(rootComment.kids)
}
})
console.log(rootComments)
rootComments.map(comment => console.log(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)
}
})
}))
);
}
Run Code Online (Sandbox Code Playgroud)
It seems like it doesn't work, I can't render rootComments.map(comment => comment.kidsText) and I can't log it as rootComments.map(comment => console.log(Object.values(comment))) (acts like there's no new kidsText property) or as rootComments.map(comment => console.log(comment.kidsText)) (returns empty array).
But. When I log console.log(rootComments) it returns array of objects with new kidsText property.
My first thought was that useEffect() doesn't wait for rootComments to fetch inside another component but it doesn't seem to be a problem so maybe it's something inside fetchKidsText() or with the way it interacts with useEffect()?
A few things are wrong with this code:
rootComments object without using setState (react can't update from it)map for iteration but discard the result.then in async / await functionPromise.all and instead await it.map is not a for loop, either use .forEach or a for..of loop
至于您的实际问题,我的第一点可能是主要问题,请显示更多代码以便我们确认
编辑建议的替代代码:
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 }
})
}
Run Code Online (Sandbox Code Playgroud)
不要按原样使用此代码,我没有测试它只是为了解释我将如何尝试用注释解决您的问题来解释我的共鸣。
祝你好运 !
| 归档时间: |
|
| 查看次数: |
146 次 |
| 最近记录: |