You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免React Native中FlatList调用API分页加载时出现重复数据

问题原因
  • 状态更新的闭包陷阱:你在useEffect中调用setRepos时直接使用了当前作用域捕获的repos变量,当分页请求并发返回、或者状态更新异步延迟时,repos可能还是旧值,导致新拉取的列表拼接在旧版本的repos后面,出现重复/漏项问题。
  • 分页状态更新的时序问题:setPage是异步操作,你在调用setPage(page + 1)后立刻设置loading = true,但此时page还没有完成更新,极端情况下可能出现同一页被请求多次的情况。
  • 排序稳定性问题:Github搜索接口当大量仓库星标数一致时,分页的排序结果会出现漂移,也可能导致不同页返回重复条目。
修复代码
export default function App() {
  const [repos, setRepos] = useState([]);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const getRepos = async () => {
      setLoading(true);
      try {
        const res = await axios.get(
          `https://api.github.com/search/repositories?q=created:>2020-01-01&sort=stars&order=desc&page=${page}&per_page=30`
        );
        const data = res.data;
        // 改用函数式更新,始终基于最新的仓库列表拼接
        setRepos(prevRepos => {
          // 新增去重逻辑,避免排序漂移导致的重复
          const existIds = new Set(prevRepos.map(item => item.id));
          const newItems = data.items.filter(item => !existIds.has(item.id));
          return [...prevRepos, ...newItems];
        });
      } catch (err) {
        console.error('拉取仓库失败', err);
      } finally {
        setLoading(false);
      }
    };
    getRepos();
  }, [page]);

  const scrollToEnd = () => {
    if (!loading) {
      // 页码更新也用函数式写法,确保拿到最新值
      setPage(prevPage => prevPage + 1);
    }
  };

  const renderItem = ({ item }) => (
    <Text className="boxed">
      Stars: {item.stargazers_count} Id: {item.id}
    </Text>
  );

  return (
    <SafeAreaView style={styles.screen}>
      <View style={styles.container}>
        <FlatList
          data={repos}
          renderItem={renderItem}
          keyExtractor={(item) => item.id.toString()} // 确保key为字符串,避免潜在异常
          onEndReached={scrollToEnd}
          onEndReachedThreshold={0.5} // 滚动到距离底部50%可视区域时触发加载,减少误触发
          showsVerticalScrollIndicator={false}
        />

        {loading && <Text className="loading">...loading</Text>}
      </View>

      <StatusBar style="auto" />
    </SafeAreaView>
  );
}
核心修改点
  • 把setRepos改为函数式更新,避免闭包捕获旧状态导致的拼接错误
  • 新增基于仓库ID的去重逻辑,解决Github搜索接口排序不稳定导致的重复条目问题
  • 调整loading的更新时机,放到请求的finally块中,避免请求失败后加载状态锁死
  • setPage也改为函数式更新,确保拿到的是最新的页码值
  • 给keyExtractor的返回值转为字符串,避免数字类型ID作为key的潜在异常
  • 增加onEndReachedThreshold参数,控制加载更多的触发频率,减少误触发

内容的提问来源于stack exchange,提问作者taha maatof

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 10:54:02