React Native从JSON API追加数据的最优方案及性能问题解决
问题根源及解决方案
1. 核心问题:重复请求相同数据导致数据冗余
你的loadMoreData每次请求的都是同一个API地址,没有传递分页参数,导致每次返回的10条数据都是重复的。data数组不断累积重复项,到50-60条时实际是重复了5-6次的相同内容,FlatList需要渲染的项暴增,直接拖慢了应用性能。
2. 次要问题:不必要的组件重渲染
renderItem里的<Text>组件没有做memo化处理,每次data更新时,所有可见的列表项都会重新渲染loadMoreData函数没有被稳定化,导致每次组件渲染时都会创建新的函数实例,触发Button的不必要重渲染- 状态更新依赖当前data快照,存在闭包风险,异步请求完成时可能拿到旧的data状态
修复后的完整代码
import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, Button, FlatList, ActivityIndicator } from 'react-native'; const API_URL = 'https://my-api-url.com/data'; // 把列表项组件memo化,避免不必要重渲染 const ListItem = React.memo(({ item }) => { return <Text>{item.name}</Text>; }); const App = () => { const [data, setData] = useState([]); const [page, setPage] = useState(1); const [isLoading, setIsLoading] = useState(false); // 用useCallback稳定函数引用 const fetchData = useCallback(async (currentPage = 1) => { setIsLoading(true); try { // 传递分页参数给API,获取对应页码的数据 const response = await fetch(`${API_URL}?page=${currentPage}`); const jsonData = await response.json(); if (currentPage === 1) { // 首次加载直接替换数据 setData(jsonData); } else { // 加载更多用函数式更新,避免依赖当前data的闭包问题 setData(prevData => [...prevData, ...jsonData]); } } catch (error) { console.error(error); } finally { setIsLoading(false); } }, []); useEffect(() => { fetchData(); }, [fetchData]); const loadMoreData = useCallback(async () => { if (isLoading) return; // 防止重复加载 const nextPage = page + 1; await fetchData(nextPage); setPage(nextPage); }, [page, isLoading, fetchData]); return ( <View> <FlatList data={data} renderItem={({ item }) => <ListItem item={item} />} keyExtractor={(item) => item.id.toString()} // FlatList性能优化参数 removeClippedSubviews={true} maxToRenderPerBatch={10} windowSize={5} /> <View style={{ padding: 10 }}> {isLoading ? ( <ActivityIndicator size="small" color="#0000ff" /> ) : ( <Button title="Load more" onPress={loadMoreData} /> )} </View> </View> ); }; export default App;
关键优化点说明
- 分页参数传递:给API添加
page参数,确保每次加载更多都获取新的10条数据,避免数据冗余 - memo化列表项:用
React.memo包裹ListItem,只有当item变化时才重新渲染 - 稳定函数引用:用
useCallback包裹fetchData和loadMoreData,避免因函数实例变化导致的组件重渲染 - 函数式状态更新:
setData(prevData => [...prevData, ...jsonData]),不依赖当前data的快照,避免异步请求中的闭包问题 - 加载状态控制:添加
isLoading状态,防止重复点击Load More按钮 - FlatList性能参数:设置
removeClippedSubviews、maxToRenderPerBatch、windowSize,优化列表渲染性能
内容的提问来源于stack exchange,提问作者John Brew
相关产品推荐
相关产品推荐

