【问题标题】:React Native Flat List (Infinite Scroll) is returning the duplicate records from FirebaseReact Native Flat List (Infinite Scroll) 正在从 Firebase 返回重复记录
【发布时间】:2019-09-21 09:41:03
【问题描述】:

我能够让 Infinite Scroll 与 React Native 和 Firebase 一起使用,但在检索接下来的 6 个文档时出现问题(限制设置为 6 个)。一旦列表的末尾被刷新,它会返回另一个 6,但它是相同的 6 个文档附加到之前相同的 6 个文档。

每次呈现 6 条记录时,我的 startAt 都会增加,并且 startAt 会以适当的数量增加。不确定我是否遗漏了某些内容,或者是否可能是异步问题?

// 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

【问题讨论】:

    标签: javascript reactjs firebase react-native google-cloud-firestore


    【解决方案1】:

    查询得到相同的结果,因为它总是从相同的偏移量开始:startAt: 0

    要修复,保持pageNumber 处于状态,随着用户滚动而前进,然后startAt: pageNumber*6

    关于代码的其他几个方面:状态可以简化...

    this.state = {
      data: [],
      limit: 6,
      // startAt removed.  start at the end of data
      loading: false
    };
    

    不需要retrieveMore。它与retrieveUsers 相同。 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.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);
      }
    };
    

    请注意,startAt 被计算为已检索数据的长度。这也适用于数据数组为空的情况。请注意,get 之后更新状态的逻辑对于第一次或第 n 次获取是相同的:将新数据附加到现有数据。

    您不需要retrieveMore。它与retrieveUsers 相同。 retrieveUsers可以简化...

    // ...
    onEndReached={this.retrieveUsers}
    

    【讨论】:

    • 我的 startAt 已经处于状态 (this.state.startAt) 并且每次执行函数时都会更新 6。所以 startAt 从 0 到 6 等等。我错过了什么吗?
    • 对不起,我错过了你推进 startAt 的逻辑。更仔细地审查,有一些简化应该使代码更容易调试(至少,也许它会发现一个修复)。一个关键的想法是 startAt 不需要(我认为不应该)预先计算。始终从存在的数据的末尾索引开始。另外,删除了一些我认为无关的逻辑路径。
    【解决方案2】:

    Flatlist 可能会调用您的检索方法两次。所以一定要使用loading 属性来阻止方法运行。

    onEndReached={(foo)=>{
      if (this.state.loading === false){
       this.makeAPizza(foo);
     }
    }}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-07
      • 1970-01-01
      • 1970-01-01
      • 2017-11-01
      • 2020-11-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多