FlatList每个元素如何从Firebase获取数据并避免无限循环?
问题根源
你现在的代码有三个核心错误:
- 绝对不能在
renderItem渲染函数里直接执行状态更新操作,render是纯函数,状态更新会触发组件重渲染,重渲染又会调用renderItem执行状态更新,自然形成无限循环 - 你只定义了单个
event状态存储单条事件数据,所有列表项共用同一个状态,自然只会渲染同一个条目的数据 eventFetched是全局状态,所有列表项共享这个加载标记,当然只会触发一次查询
解决方法
提供两种常用的实现方案,根据你的实际场景选择即可:
方案1:提前批量查询所有事件数据(适合eventId数量不多的场景)
直接在页面初始化时把所有eventId对应的事件全部查出来存到数组里,FlatList直接用查询结果渲染,逻辑最简洁:
const EventScreen = () => { // 存储所有查询到的事件数据 const [eventList, setEventList] = useState([]); const [loading, setLoading] = useState(true); const eventIds = [{id:'1', eventId: 'jaelfmk130'}, {id:'2', eventId: '1jlk335n1'}] // 页面初始化时批量查询所有事件 useEffect(() => { const fetchAllEvents = async () => { const events = await Promise.all( eventIds.map(async (item) => { const eventData = await firestore.getSingleEventDataFireStore(item.eventId); // 把原列表的id带上,方便FlatList做key return { ...eventData, listId: item.id }; }) ); setEventList(events); setLoading(false); }; fetchAllEvents(); }, []); const renderItem = ({ item }) => { return ( <View><Text>{item.title}</Text></View> ) } if (loading) return <View><Text>加载中...</Text></View>; return ( <View> <FlatList data={eventList} keyExtractor={(item) => item.listId} renderItem={renderItem} /> </View> ) }
方案2:抽离单独的列表项组件,内部管理自己的查询逻辑(适合eventId数量多,需要懒加载的场景)
把每个列表项做成独立组件,自己管理自己的加载状态和事件数据,互不干扰,也不会触发父组件的全局重渲染:
首先定义子组件:
// 单独的事件列表项组件 const EventItem = ({ eventId }) => { const [event, setEvent] = useState(null); const [loading, setLoading] = useState(true); // 子组件自己内部查询数据,和其他列表项完全隔离 useEffect(() => { const fetchEvent = async () => { const eventData = await firestore.getSingleEventDataFireStore(eventId); setEvent(eventData); setLoading(false); }; fetchEvent(); }, [eventId]); if (loading) return <View><Text>加载中...</Text></View>; if (!event) return <View><Text>事件不存在</Text></View>; return ( <View><Text>{event.title}</Text></View> ) };
父组件直接调用即可:
const EventScreen = () => { const eventIds = [{id:'1', eventId: 'jaelfmk130'}, {id:'2', eventId: '1jlk335n1'}] const renderItem = ({ item }) => { return <EventItem eventId={item.eventId} /> } return ( <View> <FlatList data={eventIds} keyExtractor={(item) => item.id} renderItem={renderItem} /> </View> ) }
内容的提问来源于stack exchange,提问作者kartoffelkiste
相关产品推荐
相关产品推荐

