React Native列表仅渲染20项求助:150条数据无法全部加载
问题解决:仅渲染20条数据的原因及修复方案
核心原因:Yelp API默认返回限制
Yelp的Business Search API默认只返回20条数据,你当前的请求没有添加分页参数,所以实际只拿到了第一页的20条数据,并非渲染逻辑问题。要获取更多数据,需要通过offset参数实现分页请求。
修复步骤
1. 新增分页相关状态
在HomeScreen中添加分页所需的状态变量:
const [serviceData, setServiceData] = useState(localServices) const [city, setCity] = useState("San Francisco") const [activeTab, setActiveTab] = useState("Delivery"); const [loading, setLoading] = useState(false) // 新增分页状态 const [offset, setOffset] = useState(0) const [hasMore, setHasMore] = useState(true) // 标记是否还有更多数据可加载
2. 修改API请求函数,支持分页并合并数据
修改getServicesFromYelp函数,添加offset参数,并且将新请求到的数据合并到现有数据中(而非直接替换):
const getServicesFromYelp = (isLoadMore = false) => { // 给请求URL添加offset和limit参数 const yelpUrl = `https://api.yelp.com/v3/businesses/search?term=Home+Services&location=${city}&offset=${offset}&limit=20`; const apiOptions = { headers: { Authorization: `Bearer ${YELP_API_KEY}`, }, }; setLoading(true) return fetch(yelpUrl, apiOptions) .then((res) => res.json()) .then((json) => { setLoading(false) if(json.error) return Alert.alert('Sorry', json.error.description); const newData = json?.businesses?.filter(business => business) || [] // 加载更多时合并数据,首次请求时替换数据 if (isLoadMore) { setServiceData(prev => [...prev, ...newData]) // 返回数据不足20条,说明没有更多数据了 setHasMore(newData.length === 20) } else { setServiceData(newData) setHasMore(newData.length === 20) } } ); };
3. 切换城市/标签时重置分页
当切换城市或标签时,需要重置分页起始位置和数据:
useEffect(() => { setOffset(0) // 重置分页起始点 getServicesFromYelp(); }, [city, activeTab]);
4. 替换ScrollView为FlatList,实现滚动加载更多
原代码用ScrollView包裹所有内容会导致性能问题,且无法触发滚动加载逻辑。将主容器换成FlatList,把头部元素作为ListHeaderComponent,并添加滚动触底加载更多的逻辑:
修改HomeScreen的return部分:
return ( <Screen style={tailwind`bg-white flex-1`}> <FlatList style={tailwind`flex-1`} showsVerticalScrollIndicator={false} data={serviceData} keyExtractor={(item) => item.id} // 改用唯一id作为key,避免index导致的渲染异常 ListHeaderComponent={() => ( <> <HeaderTabs activeTab={activeTab} setActiveTab={setActiveTab} /> <SearchBar setCity={setCity} city={city} /> <Categories /> {loading && <ActivityIndicator size="large" color={colors.primary} style={tailwind`mt-2 mb-6`} />} </> )} renderItem={({item}) => <ServiceItemCard item={item} />} // 滚动到距离底部10%位置时触发加载更多 onEndReached={() => { if (hasMore && !loading) { setOffset(prev => prev + 20) getServicesFromYelp(true) } }} onEndReachedThreshold={0.1} // 底部加载状态指示器 ListFooterComponent={() => { if (hasMore && loading) { return <ActivityIndicator size="small" color={colors.primary} style={tailwind`py-4`} /> } return null }} /> </Screen> );
5. 移除冗余的ServiceItem组件
现在直接通过FlatList的renderItem渲染ServiceItemCard,可以删除ServiceItem组件简化结构。
额外优化点
- 图片加载优化:给
Image组件添加默认占位图,避免图片加载失败时显示空白:
<Image source={{ uri: item.image_url || 'https://via.placeholder.com/300x200' }} style={tailwind`w-full h-48 rounded-lg`} resizeMode="cover" />
验证效果
修改完成后,滚动到列表底部时会自动请求下一页数据,直到没有更多内容为止,此时就能看到超过20条的卡片了。
内容的提问来源于stack exchange,提问作者Lance Nieva
相关产品推荐
相关产品推荐

