使用FlatList实现无限滚动时加载更多数据致应用无响应
React Native FlatList无限滚动UI无响应问题解决方案
问题根源分析
- 重复加载同一页数据:
handleLoadMore中page固定为1,每次加载都是第一页数据,重复累加会导致FlatList重渲染时阻塞UI线程。 - 错误混用Apollo缓存与本地状态:直接在
updateQuery里调用setUsers,导致Apollo缓存更新和本地状态更新冲突,引发不必要的重渲染,加重UI负担。 - 无重复请求拦截:滚动到底部时可能多次触发
onEndReached,同时发起多个请求,阻塞JS线程,导致点击事件、日志输出完全无响应。 - 初始渲染配置不合理:
initialNumToRender设为1,会让FlatList频繁触发渲染,进一步消耗UI资源。
解决方案
- 跟踪页码并递增:用状态保存当前页码,每次加载更多时自动+1,确保请求下一页数据。
- 依赖Apollo缓存管理数据:移除本地
users状态,直接使用useQuery返回的data,由Apollo自动处理缓存和数据更新,避免状态不一致。 - 添加加载状态锁:维护
isLoadingMore状态,防止请求未完成时重复触发加载。 - 正确实现
updateQuery:返回合并后的查询结果,让Apollo自动更新缓存,组件从缓存获取最新数据。 - 优化FlatList属性:调整
initialNumToRender为合理值,减少初始渲染压力;设置合适的onEndReachedThreshold,避免过早/过晚触发加载。
修改后的完整代码
import { FlatList, Text } from "react-native"; import * as S from "./styles"; import { useQuery } from "@apollo/client"; import { searchUsers } from "src/services/users/graphql/query"; import React, { useState } from "react"; import { getImagePathFromObj } from "@helpers/getImagePath"; export const Playground = () => { const [currentPage, setCurrentPage] = useState(1); const [isLoadingMore, setIsLoadingMore] = useState(false); const { loading, error, data, fetchMore } = useQuery(searchUsers, { variables: { name: "", latestLatitude: 64.71998823308158, latestLongitude: 175.5945099215997, page: currentPage, }, onError: (error) => { console.error("Error fetching users:", error); }, }); const handleLoadMore = async () => { if (isLoadingMore) return; // 拦截重复请求 setIsLoadingMore(true); try { await fetchMore({ variables: { name: "", latestLatitude: 64.71998823308158, latestLongitude: 175.5945099215997, page: currentPage + 1, }, updateQuery: (previousResult, { fetchMoreResult }) => { if (!fetchMoreResult?.searchUsers) return previousResult; // 返回合并结果,让Apollo自动更新缓存 return { searchUsers: [...previousResult.searchUsers, ...fetchMoreResult.searchUsers] }; }, }); setCurrentPage(prev => prev + 1); } catch (err) { console.error("Error loading more users:", err); } finally { setIsLoadingMore(false); } }; const RenderItem = React.memo(({ item }) => { return ( <S.Profile onPress={() => console.log("press")}> <S.ProfileImage source={{ uri: getImagePathFromObj(item) }} /> </S.Profile> ); }); return ( <S.Container> {loading && !isLoadingMore && <Text>Loading...</Text>} {error && <Text>Error loading users</Text>} <FlatList data={data?.searchUsers || []} renderItem={({ item }) => <RenderItem item={item} />} keyExtractor={(item) => item.id.toString()} numColumns={2} onEndReached={handleLoadMore} onEndReachedThreshold={0.5} initialNumToRender={10} ListFooterComponent={isLoadingMore && <Text>Loading more...</Text>} /> </S.Container> ); };
关键修改说明
- 移除本地
users状态,直接使用Apollo返回的data,避免状态冲突。 - 新增
currentPage和isLoadingMore状态,分别控制页码和请求锁。 updateQuery正确返回合并结果,让Apollo自动管理缓存更新。- 优化FlatList配置,添加底部加载提示,提升用户体验。
内容的提问来源于stack exchange,提问作者Sky Canvas
相关产品推荐
相关产品推荐

