问题
I was able to get Infinite Scroll working with React Native and Firebase, but there's an issue on retrieving the next 6 documents (limit is set to 6). It returns another 6 once the end of the list is refreshed, but it's the same 6 documents appended to the previous same 6 documents.
I have the startAt increase each time 6 records are rendering and the startAt is increasing at the right amount. Not sure if I'm missing something or if it could be an async issue?
// Imports: Dependencies
import React, { Component } from "react";
import { ActivityIndicator, Dimensions, FlatList, View, SafeAreaView, StyleSheet } from 'react-native';
import * as firebase from 'firebase';
import 'firebase/firestore';
import firebaseConfig from '../config/config';
// Imports: Components
import UserSelector from '../components/UserSelector';
import TitleLarge from '../components/TitleLarge';
// Screen Dimensions
const { height, width } = Dimensions.get('window');
// Screen: Flat List (Users)
class FlatListUsers extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
startAt: 0,
limit: 6,
loading: false,
};
}
// Component Will Mount
componentWillMount = () => {
// Firebase: Initialize
firebase.initializeApp({
apiKey: `${firebaseConfig.apiKey}`,
authDomain: `${firebaseConfig.authDomain}`,
databaseURL: `${firebaseConfig.databaseURL}`,
projectId: `${firebaseConfig.projectId}`,
storageBucket: `${firebaseConfig.storageBucket}`,
messagingSenderId: `${firebaseConfig.messagingSenderId}`,
});
}
// Component Did Mount
componentDidMount = () => {
this.retrieveUsers();
}
// Retrieve Users
retrieveUsers = async () => {
try {
// Set State: Loading
this.setState({ loading: true });
// Firebase: Database + Settings
const db = firebase.firestore();
// Query
console.log('Fetching Users')
const query = await db.collection('users')
.where('company', '==', 'Google')
.orderBy('first_name')
.startAt(this.state.startAt)
.limit(this.state.limit);
// Query Snapshot
const querySnapshot = await query.get();
// Document Data
console.log('Document Data');
const documentData = querySnapshot.docs.map(document => document.data());
// console.log(documentData);
// Set State: Initial Query
if (this.state.startAt <= this.state.limit) {
// Set State
this.setState({
data: documentData,
startAt: this.state.startAt + this.state.limit + 1,
loading: false,
refreshing: false,
})
}
// Set State: Refreshing Queries
else {
// Set State
this.setState({
data: [...this.state.data, ...documentData],
startAt: this.state.startAt + this.state.limit + 1,
loading: false,
refreshing: false,
})
}
// Start At
console.log(`StartAt: ${this.state.startAt}`);
}
catch (error) {
console.log(error);
}
};
// Retrieve More Users
retrieveMore = async () => {
try {
// Set State + Retrieve Users
this.setState({
loading: true,
}, async () => {
await this.retrieveUsers();
})
// Set State
this.setState({
loading: false,
})
}
catch (error) {
console.log(error);
}
};
// Render Header
renderHeader = () => {
try {
return (
<View style={styles.activityIndicator}>
<TitleLarge title="Users" />
</View>
)
}
catch (error) {
console.log(error);
}
};
// Render Footer
renderFooter = () => {
try {
// Check If Loading
if (this.state.loading) {
return <ActivityIndicator />
}
else {
return null;
}
}
catch (error) {
console.log(error);
}
};
render() {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<UserSelector
key={(item, index) => {
return item.id;
}}
firstName={item.first_name}
lastName={item.last_name}
company={item.company}
/>
)}
keyExtractor={( item ) => {
return item.id;
}}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
onEndReached={this.retrieveMore}
onEndReachedThreshold={0}
/>
</SafeAreaView>
)
}
}
// Styles
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
height: height,
width: width,
borderTopWidth: 0,
borderBottomWidth: 0,
},
scrollView:{
height: 'auto',
},
UserContainer: {
width: width,
marginBottom: 7,
},
itemText: {
fontFamily: 'System',
fontSize: 17,
fontWeight: '400',
color: '#222222',
marginLeft: 16,
},
activityIndicator: {
paddingVertical: 20,
borderTopWidth: 0,
borderTopColor: '#CED0CE',
},
});
// Exports
export default FlatListUsers
回答1:
Flatlist may call your retrieval method twice. So be sure to use the loading prop to prevent the method from running.
onEndReached={(foo)=>{
if (this.state.loading === false){
this.makeAPizza(foo);
}
}}
回答2:
The query gets the same results because it always starts at the same offset: startAt: 0.
To fix, keep a pageNumber in state, advanced as the user scrolls, then startAt: pageNumber*6
A few other comments about the code: State can be simplified...
this.state = {
data: [],
limit: 6,
// startAt removed. start at the end of data
loading: false
};
Don't need retrieveMore. Its the same as retrieveUsers. retrieveUsers can be simplified...
// Retrieve Users
retrieveUsers = async () => {
try {
// Set State: Loading
this.setState({ loading: true });
// Firebase: Database + Settings
const db = firebase.firestore();
// Query
console.log('Fetching Users')
const query = await db.collection('users')
.where('company', '==', 'Google')
.orderBy('first_name')
.startAt(this.state.data.length)
.limit(this.state.limit);
// Query Snapshot
const querySnapshot = await query.get();
// Document Data
console.log('Document Data');
const documentData = querySnapshot.docs.map(document => document.data());
// console.log(documentData);
// Set State
this.setState({
data: [...this.state.data, ...documentData],
loading: false
})
}
catch (error) {
console.log(error);
}
};
Notice that startAt is computed to be the length of data already retrieved. This works when data array is empty, also. Notice that logic to update state after the get is the same for the first or nth get: append new data to the existing data.
You don't need retrieveMore. Its the same as retrieveUsers. retrieveUsers can be simplified...
// ...
onEndReached={this.retrieveUsers}
来源:https://stackoverflow.com/questions/55959697/react-native-flat-list-infinite-scroll-is-returning-the-duplicate-records-from