Firestore implementation continuous scrolling and load more items in a FlatList
Wed May 15 2024 05:37:28 GMT+0000 (Coordinated Universal Time)
Saved by @masangare33 #eventelysium #flatlist #firestore
//Regular import React, { useState, useEffect } from 'react'; import { View, FlatList, ListItem, Button, Avatar } from 'react-native'; import firestore from '@react-native-firebase/firestore'; // Assuming filteredData is your initial data source const YourComponent = () => { const [visibleData, setVisibleData] = useState([]); const [isLoading, setIsLoading] = useState(false); const [lastVisible, setLastVisible] = useState(null); useEffect(() => { fetchData(); }, []); const fetchData = async () => { setIsLoading(true); try { const querySnapshot = await firestore() .collection('your_collection') .orderBy('createdAt', 'desc') .limit(10) .get(); const newData = querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })); setVisibleData(newData); setLastVisible(querySnapshot.docs[querySnapshot.docs.length - 1]); } catch (error) { console.error('Error fetching data: ', error); } finally { setIsLoading(false); } }; const fetchMoreData = async () => { setIsLoading(true); try { const querySnapshot = await firestore() .collection('your_collection') .orderBy('createdAt', 'desc') .startAfter(lastVisible) .limit(10) .get(); const newData = querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })); setVisibleData((prevData) => [...prevData, ...newData]); setLastVisible(querySnapshot.docs[querySnapshot.docs.length - 1]); } catch (error) { console.error('Error fetching more data: ', error); } finally { setIsLoading(false); } }; const handleEndReached = () => { if (!isLoading) { fetchMoreData(); } }; return ( <FlatList data={visibleData} keyExtractor={(item) => item.id} ListEmptyComponent={() => isLoading ? <EventMenuProduct /> : <NoData /> } onEndReached={handleEndReached} onEndReachedThreshold={0.1} // Adjust this threshold as needed renderItem={({ item, index }) => ( <View key={index} style={{ alignContent: 'center', alignSelf: 'center', }} > {/* Your existing renderItem logic */} </View> )} /> ); }; export default YourComponent; /// With my code import React, { useState, useEffect } from 'react'; import { View, FlatList, ListItem, Button, Avatar } from 'react-native'; import { collection, getDocs, onSnapshot } from 'firebase/firestore'; import { db } from 'your-firebase-config-file'; // Import your Firebase database config // Assuming filteredData is your initial data source const YourComponent = ({ category }) => { const [products, setProducts] = useState([]); const [isLoading, setIsLoading] = useState(false); const [lastDoc, setLastDoc] = useState(null); useEffect(() => { fetchMenuData(); }, []); const fetchMenuData = async () => { setIsLoading(true); try { const subCollectionNames = getCategorySubCollectionNames(category); const allProducts = []; const subCollectionPromises = subCollectionNames.map(async (subCollectionName) => { const subCollectionRef = collection(db, `vehicles/${category}/${subCollectionName}`); const subCollectionSnapshot = await getDocs(subCollectionRef); subCollectionSnapshot.forEach((doc) => { allProducts.push({ id: doc.id, ...doc.data() }); }); const unsubscribe = onSnapshot(subCollectionRef, (snapshot) => { snapshot.docChanges().forEach((change) => { if (change.type === 'added') { setProducts((prevProducts) => [...prevProducts, { id: change.doc.id, ...change.doc.data() }]); } }); }); return () => unsubscribe(); }); await Promise.all(subCollectionPromises); setIsLoading(false); } catch (error) { console.error('Error fetching menu data:', error); setIsLoading(false); } }; const getCategorySubCollectionNames = (category) => { switch (category) { case 'Buying': return ['subCollectionName1', 'subCollectionName2']; // Adjust with your subcollection names case 'Renting': return ['subCollectionName3', 'subCollectionName4']; // Adjust with your subcollection names default: return []; } }; const handleEndReached = () => { if (!isLoading) { fetchMoreData(); } }; const fetchMoreData = async () => { setIsLoading(true); try { const subCollectionNames = getCategorySubCollectionNames(category); const allProducts = []; const subCollectionPromises = subCollectionNames.map(async (subCollectionName) => { const subCollectionRef = collection(db, `vehicles/${category}/${subCollectionName}`); const query = lastDoc ? subCollectionRef.startAfter(lastDoc) : subCollectionRef; const subCollectionSnapshot = await getDocs(query); subCollectionSnapshot.forEach((doc) => { allProducts.push({ id: doc.id, ...doc.data() }); }); const lastDocument = subCollectionSnapshot.docs[subCollectionSnapshot.docs.length - 1]; setLastDoc(lastDocument); return allProducts; }); const productsArray = await Promise.all(subCollectionPromises); const mergedProducts = productsArray.reduce((acc, curr) => acc.concat(curr), []); setProducts((prevProducts) => [...prevProducts, ...mergedProducts]); setIsLoading(false); } catch (error) { console.error('Error fetching more data:', error); setIsLoading(false); } }; return ( <FlatList data={products} keyExtractor={(item) => item.id} ListEmptyComponent={() => isLoading ? <EventMenuProduct /> : <NoData />} onEndReached={handleEndReached} onEndReachedThreshold={0.1} renderItem={({ item }) => ( <View style={{ /* Your styling */ }}> {/* Your rendering logic */} </View> )} /> ); }; export default YourComponent;
Comments