Reputation: 867
this code is supposed to load infinite data using pagination with RTK Query and Flash list. Data is coming normally without issues the only issue is it loads all data at once and ignores the onEndReached functionality. after monitoring the server once the page loads it loads all 5 pages at once without even touching the list
import React, { useState } from "react";
import { View, StyleSheet, FlatList } from "react-native";
import { useGetLatestArticlesQuery } from "../data/articleQuery";
import { ActivityIndicator } from "react-native";
import ArticleListItem from "./articleSingleItem";
const HomeArticlesList = ({ limit }) => {
[page, setPage] = React.useState(1);
const [isLoadingMore, setIsLoadingMore] = useState(false);
const { data, isLoading, refetch } = useGetLatestArticlesQuery(limit, page);
if (isLoading) {
// Render loading state or placeholder
return <ActivityIndicator size="large" />;
}
const renderItem = ({ item }) => {
// Check if item is defined before rendering
if (!item) {
console.warn("Item is null or undefined:", item);
return null;
}
return <ArticleListItem item={item} />;
};
const keyExtractor = (item) =>
item ? item.id.toString() : Math.random().toString();
const renderSeparator = () => {
return <View style={styles.separator} />;
};
if (isLoadingMore) {
// Render loading state or placeholder
return <ActivityIndicator size="large" />;
}
const onEndReached = () => {
setIsLoadingMore(true);
setPage(page + 1);
if (page != 1 && page < 5) {
refetch();
}
setIsLoadingMore(false);
};
return (
<View>
<View style={styles.container}>
<FlatList
disableVirtualization={true}
removeClippedSubviews={true}
maxToRenderPerBatch={60}
windowSize={30}
data={data}
renderItem={renderItem}
keyExtractor={keyExtractor}
ItemSeparatorComponent={renderSeparator}
onEndReached={onEndReached}
onEndReachedThreshold={0.5}
estimatedItemSize={100}
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
height: "100%",
padding: 12,
},
separator: {
height: 10,
backgroundColor: "transparent",
},
});
export default HomeArticlesList;
RTK query functions
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({
query: (category_id) => ({
url: `/articles?category=${category_id}&limit=20&page=${page}`,
method: "GET",
}),
// Always merge incoming data to the cache entry
merge: (currentCache, newItems) => {
currentCache.push(...newItems);
},
// Refetch when the page arg changes
forceRefetch({ currentArg, previousArg }) {
return currentArg !== previousArg;
},
providesTags: (result, error, category_id, page) =>
result
? [{ type: "articlesByCategory", id: category_id, page: 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",
}),
// Always merge incoming data to the cache entry
merge: (currentCache, newItems) => {
currentCache.push(...newItems);
},
// Refetch when the page arg changes
forceRefetch({ currentArg, previousArg }) {
return currentArg !== previousArg;
},
providesTags: (result, error, limit, page) =>
result ? [{ type: "latestArticles", limit: limit, page: page }] : [],
}),
getRelatedArticles: builder.query({
query: (article_id) => ({
url: `/articles/related/${article_id}?limit=10&page=${page}`,
method: "Get",
}),
// Always merge incoming data to the cache entry
merge: (currentCache, newItems) => {
currentCache.push(...newItems);
},
// Refetch when the page arg changes
forceRefetch({ currentArg, previousArg }) {
return currentArg !== previousArg;
},
providesTags: (result, error, article_id, page) =>
result
? [{ type: "relatedArticles", article_id: article_id, page: page }]
: [],
}),
}),
});
export const {
useGetArticlesByCategoryQuery,
useGetFeaturedArticlesQuery,
useGetLatestArticlesQuery,
useGetRelatedArticlesQuery,
} = articlesApi;
i kept track of
const onEndReached = () => {
setIsLoadingMore(true);
setPage(page + 1);
if (page != 1 && page < 5) {
console.log(page);
refetch();
}
by logging anything just to watch how it works and unfortunately it prints all page numbers once the app loaded without even touching the list
Upvotes: -2
Views: 1018
Reputation: 1
Try sending data such that the component rendering the list is filling up the space. Either reduce your list component container size or increase data coming through (use mock). You have to make sure the data coming on first call is filling the container. You can try sending too much data in the first call to see if on scroll the onEndReached is called or not.
Upvotes: 0
Reputation: 1
const [onEnd, setOnEnd] = useState<boolean>(true);
onMomentumScrollBegin={() => setOnEnd(false)}
onEndReached={() => {
if (!onEnd) {
onEndReached();
}
}}
Upvotes: 0
Reputation: 3649
I expect that onEndReached
were instantly triggered due to value of onEndReachedThreshold
which will call refetch
which trigger a rerender and so on...
To test my assumption increase the row height to for instance to 300 so that
onEndReachedThreshold
only get called 4 times
Upvotes: 0