[英]setState loop seems to only run on the last iteration
So I have an app with friends and events, where each friends has specific events.所以我有一个包含朋友和活动的应用程序,每个朋友都有特定的活动。
I just want to retrieve every single event from every single friend.我只想从每个朋友那里检索每个事件。
I have an 'event' state const [events, setEvents] = useState([]);
我有一个“事件” state
const [events, setEvents] = useState([]);
Then here is the problematic useEffect snippet:然后是有问题的useEffect片段:
useEffect(() => {
getFriendsIds()
.then(idsArray => {
Promise.all(idsArray.map(id => {
getUserEvents(id)
.then(evs => {
if (evs.length > 0) {
for (let i=0; i<evs.length; i++) {
setEvents([...events, evs[i]]);
}
}
})
}))
})
}, [])
This should store the aforementioned events in the 'events' state variable.这应该将上述事件存储在“事件” state变量中。
However, when I try to render them with {events.map(ev => renderItem(ev))}
, I only get the very last event of the last friend in the loop (It is guaranteed that renderItem works fine).但是,当我尝试使用
{events.map(ev => renderItem(ev))}
渲染它们时,我只得到循环中最后一个朋友的最后一个事件(保证 renderItem 工作正常)。
I would love an explanation of how this works, and if possible an alternative algorithm that actually achieves what I aim to do.我很想解释它是如何工作的,如果可能的话,还有一个替代算法可以真正实现我的目标。
Thanks谢谢
Actually, this happens because your useEffect()
doesn't have the events
state in its dependency array.实际上,这是因为您的
useEffect()
在其依赖数组中没有events
state 。
useEffect(() => {
...
}, [events])
However event this solution will not work properly because the setState()
function works asynchronously.但是,此解决方案将无法正常工作,因为
setState()
function 异步工作。
You have to use state updater function in this case:在这种情况下,您必须使用 state 更新程序 function :
useEffect(() => {
...
setEvents((prevEvents) => [...prevEvents, evs[i]]);
...
}, []);
Read more about dependency array
and state updater
in the official documentation在官方文档中阅读有关
dependency array
和state updater
的更多信息
Try passing a function to setEvents and remove the for loop.尝试将 function 传递给 setEvents 并删除 for 循环。
if (evs.length > 0) {
setEvents((prev) => ([...prev, ...evs]));
}
Move the setState
out of the loop -将
setState
移出循环 -
useEffect(async () => {
const ids = await getFriendsIds()
const events = await Promise.all(ids.map(getUserEvents)))
setEvents(events.flat()) // replace
}, [])
If you want to append events
to the existing events state, you can use a functional update -如果要将 append
events
改为现有事件 state,可以使用功能更新 -
useEffect(async () => {
const ids = await getFriendsIds()
const events = await Promise.all(ids.map(getUserEvents)))
setEvents(r => [...r, ...events.flat()]) // append
}, [])
You can use .flat
instead of checking for .length
as it will remove empty arrays for you automatically -您可以使用
.flat
而不是检查.length
因为它会自动为您删除空的 arrays -
const a = [["event1", "event2"], [], ["event3"], ["event4"], []] console.log(a.flat()) // ["event1", "event2", "event3", "event4" ]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.