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

React Native中RTK Query+FlashList分页加载onEndReached失效问题

问题解决:RTK Query + FlatList 无限滚动初始加载全部页面

问题现象

使用RTK Query和FlatList实现无限滚动分页时,页面加载未滚动就直接拉取全部5页数据,onEndReached完全失效,日志显示页面加载时直接打印所有页码并触发全部请求。

核心问题分析

  1. RTK Query参数传递错误:useGetLatestArticlesQuery定义接收包含limit和page的对象参数,但组件中传了两个独立参数(limit, page),导致参数匹配异常,触发不必要的重复请求。
  2. onEndReached逻辑混乱:同步更新page后立即调用refetch,且直接同步设置isLoadingMore为false,忽略React状态更新的异步特性,导致逻辑触发失控;初始判断page !=1限制了第一页后的请求,但状态异步更新导致判断失效。
  3. FlatList配置不合理:开启已过时的disableVirtualization、maxToRenderPerBatch设得过大,加上onEndReachedThreshold=0.5,导致列表初始渲染时就满足触底条件,反复触发onEndReached。
  4. 加载状态处理错误:组件在isLoading或isLoadingMore时直接返回加载指示器,替换了整个列表,导致列表渲染不完整,同时触发异常的状态循环。
  5. RTK Query Endpoint配置问题:部分endpoint(如getArticlesByCategory、getRelatedArticles)中使用未定义的page变量,getLatestArticles的providesTags和forceRefetch未正确处理对象参数。

修复方案及代码修改

1. 修正RTK Query Endpoint配置

// ../data/articleQuery.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import Config from "../utils/Config";

const apiUrl = Config.API_BASE_URL;

export const articlesApi = createApi({
  reducerPath: "articlesApi",
  baseQuery: fetchBaseQuery({ baseUrl: apiUrl }),
  refetchOnFocus: true,
  refetchOnReconnect: true,
  tagTypes: [
    "articlesByCategory",
    "featuredArticles",
    "latestArticles",
    "relatedArticles",
  ],
  endpoints: (builder) => ({
    getArticlesByCategory: builder.query({
      // 修正:参数改为包含category_id和page的对象
      query: ({ category_id, page }) => ({
        url: `/articles?category=${category_id}&limit=20&page=${page}`,
        method: "GET",
      }),
      merge: (currentCache, newItems) => {
        currentCache.push(...newItems);
      },
      forceRefetch({ currentArg, previousArg }) {
        return currentArg?.page !== previousArg?.page;
      },
      providesTags: (result, error, { category_id, page }) =>
        result
          ? [{ type: "articlesByCategory", id: category_id, page }]
          : [],
    }),
    getFeaturedArticles: builder.query({
      query: () => ({ url: "/articles/featured", method: "Get" }),
      providesTags: ["featuredArticles"],
    }),
    getLatestArticles: builder.query({
      query: ({ limit, page }) => ({
        url: `/articles?limit=${limit}&page=${page}`,
        method: "Get",
      }),
      merge: (currentCache, newItems) => {
        currentCache.push(...newItems);
      },
      forceRefetch({ currentArg, previousArg }) {
        // 对比page变化来决定是否重取
        return currentArg?.page !== previousArg?.page;
      },
      providesTags: (result, error, { limit, page }) =>
        result ? [{ type: "latestArticles", limit, page }] : [],
    }),
    getRelatedArticles: builder.query({
      // 修正:参数改为包含article_id和page的对象
      query: ({ article_id, page }) => ({
        url: `/articles/related/${article_id}?limit=10&page=${page}`,
        method: "Get",
      }),
      merge: (currentCache, newItems) => {
        currentCache.push(...newItems);
      },
      forceRefetch({ currentArg, previousArg }) {
        return currentArg?.page !== previousArg?.page;
      },
      providesTags: (result, error, { article_id, page }) =>
        result
          ? [{ type: "relatedArticles", article_id, page }]
          : [],
    }),
  }),
});

export const {
  useGetArticlesByCategoryQuery,
  useGetFeaturedArticlesQuery,
  useGetLatestArticlesQuery,
  useGetRelatedArticlesQuery,
} = articlesApi;

2. 修复HomeArticlesList组件逻辑

import React, { useState, useEffect, useCallback } from "react";
import { View, StyleSheet, FlatList, ActivityIndicator } from "react-native";
import { useGetLatestArticlesQuery } from "../data/articleQuery";
import ArticleListItem from "./articleSingleItem";

const HomeArticlesList = ({ limit }) => {
  const [page, setPage] = useState(1);
  const [isLoadingMore, setIsLoadingMore] = useState(false);
  // 修正:传递对象参数给RTK Query
  const { data, isLoading, refetch } = useGetLatestArticlesQuery({ limit, page });

  // 监听page变化,触发新页面请求
  useEffect(() => {
    if (page > 1 && page <= 5 && isLoadingMore) {
      refetch().finally(() => setIsLoadingMore(false));
    }
  }, [page, isLoadingMore, refetch]);

  const renderItem = ({ item }) => {
    if (!item) {
      console.warn("Item is null or undefined:", item);
      return null;
    }
    return <ArticleListItem item={item} />;
  };

  const keyExtractor = (item) => item?.id?.toString() || Math.random().toString();

  const renderSeparator = () => (
    <View style={styles.separator} />
  );

  // 用useCallback包裹,避免每次渲染重新创建
  const onEndReached = useCallback(() => {
    if (isLoadingMore || page >=5) return;
    setIsLoadingMore(true);
    setPage(prev => prev +1);
  }, [isLoadingMore, page]);

  // 渲染底部加载指示器
  const renderFooter = () => {
    if (!isLoadingMore) return null;
    return <ActivityIndicator size="large" style={{marginVertical:10}} />;
  };

  if (isLoading && page ===1) {
    return <ActivityIndicator size="large" />;
  }

  return (
    <View style={styles.container}>
      <FlatList
        // 移除过时的disableVirtualization,默认开启虚拟化
        removeClippedSubviews={true}
        maxToRenderPerBatch={10} // 减小批量渲染数量
        windowSize={10}
        data={data || []}
        renderItem={renderItem}
        keyExtractor={keyExtractor}
        ItemSeparatorComponent={renderSeparator}
        onEndReached={onEndReached}
        onEndReachedThreshold={0.1} // 降低阈值,避免初始触发
        estimatedItemSize={100}
        ListFooterComponent={renderFooter} // 添加底部加载组件
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 12,
  },
  separator: {
    height: 10,
    backgroundColor: "transparent",
  },
});

export default HomeArticlesList;

关键修复点说明

  • 参数传递修正:统一RTK Query的参数为对象,避免参数解构错误导致的异常请求。
  • onEndReached优化:使用useCallback缓存函数,避免重复创建;通过useEffect监听page变化触发请求,利用Promise的finally正确处理加载状态。
  • FlatList配置调整:移除过时属性,降低maxToRenderPerBatch和onEndReachedThreshold,避免初始加载触发触底逻辑。
  • 加载状态处理:仅在初始加载第一页时显示全屏加载,后续加载在列表底部显示指示器,避免替换整个列表。
  • RTK Query Endpoint修正:修复未定义的page变量,优化forceRefetch逻辑,确保仅在页码变化时触发重取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 05:35:05