繁体   English   中英

React Native:当从rest api重新调整空的json数组时,停止FlatList的onEndReached的无限循环

[英]React Native: Stop endlesss loop of onEndReached of FlatList when empty json array is retuned from rest api

我正在使用互联网上提到的 react-native 的无限滚动 Flatlist 模式。 到目前为止,它有利于拥有长数据。 但是当其余 API 分页完成时,它返回空的 JSON 数组。 现在有了无限滚动模式, onEndReached 函数被无限抛出导致不必要的休息调用。 那么处理这种情况的最佳方法是什么。

来自 API 的数据可以是单行或 500 行 JSON 对象,具体取决于代码中提到的条件 URL。 在 500 行的情况下,直到有更多数据要获取时才可以,但是在最后 480-500 批之后,它变成了一个无限循环,这是一个问题。 在1行的情况下,立即变成无限循环。 我如何有条件地中断 onEndReached 事件,以便在我从 rest api 检测到空数组时它永远不会触发。

下面是我的 Flatlist 实现:

import React, { Component } from 'react';
import { StyleSheet, Text, View, FlatList, Image, ActivityIndicator, TouchableOpacity, ToastAndroid } from 'react-native';
import * as SecureStore from 'expo-secure-store';
import GLOBAL from './productglobal'
import { Ionicons } from '@expo/vector-icons';
import SearchBar from '../commoncomponents/searchbar'

export default class ProductsList extends Component {

    static navigationOptions = ({ navigation }) => {
        return {
            headerTitle: 'Products',
            headerRight: () => (
                <TouchableOpacity
                    style={{ paddingRight: 20 }}
                    onPress={() => { navigation.navigate("Settings") }}
                >
                    <Ionicons name='md-more' size={25} color='white' />
                </TouchableOpacity>
            ),
        }
    };

    constructor(props) {
        super(props);
        this.state = {
            loading: false,
            searchValue: '',
            data: [],
            page: 1,
            error: null,
            refreshing: false,
            base_url: null,
            c_key: null,
            c_secret: null,
        };
        GLOBAL.productlistScreen = this;
    }

    async componentDidMount() {
        await this.getCredentials();
        this.fetchProductList();
    }

    getCredentials = async () => {
        const credentials = await SecureStore.getItemAsync('credentials');
        const credentialsJson = JSON.parse(credentials)
        this.setState({
            base_url: credentialsJson.base_url,
            c_key: credentialsJson.c_key,
            c_secret: credentialsJson.c_secret,
        })
    }

    fetchProductList = () => {
        const { base_url, c_key, c_secret, page, searchValue } = this.state;
        let url = null
        if (searchValue) {
            url = `${base_url}/wp-json/wc/v3/products?per_page=20&search=${searchValue}&page=${page}&consumer_key=${c_key}&consumer_secret=${c_secret}`;
        } else {
            url = `${base_url}/wp-json/wc/v3/products?per_page=20&page=${page}&consumer_key=${c_key}&consumer_secret=${c_secret}`;
        }
        console.log(url)
        this.setState({ loading: true });
        setTimeout(() => {
            fetch(url).then((response) => response.json())
                .then((responseJson) => {
                    this.setState({
                        data: this.state.data.concat(responseJson),
                        error: responseJson.code || null,
                        loading: false,
                        refreshing: false
                    });
                }).catch((error) => {
                    this.setState({
                        error,
                        loading: false,
                        refreshing: false
                    })
                });
        }, 1500);
    };

    renderListSeparator = () => {
        return (
            <View style={{
                height: 1,
                width: '100%',
                backgroundColor: '#999999'
            }} />
        )
    }

    renderListFooter = () => {
        if (!this.state.loading) return null;

        return (
            <View style={{
                paddingVertical: 20,
            }}>
                <ActivityIndicator color='#96588a' size='large' />
            </View>
        )
    }

    handleRefresh = () => {
        this.setState({
            page: 1,
            refreshing: true,
            data: []
        }, () => {
            this.fetchProductList();
        }
        )
    }

    handleLoadMore = () => {
        console.log('loading triggered')
        this.setState({
            page: this.state.page + 1,
        }, () => {
            this.fetchProductList();
        })
    }

    handleSearch = (value) => {
        // console.log(value)
        this.setState({
            searchValue: value,
            page: 1,
            refreshing: true,
            data: []
        }, () => {
            this.fetchProductList()
        })
    }

    render() {
        return (
            <View style={{flex:1}}>
                <SearchBar onSearchPress={this.handleSearch}></SearchBar>
                <FlatList
                    data={this.state.data}
                    keyExtractor={item => item.id.toString()}
                    refreshing={this.state.refreshing}
                    extraData={this.state.data}
                    onRefresh={this.handleRefresh}
                    onEndReached={this.handleLoadMore}
                    onEndReachedThreshold={0.5}
                    ItemSeparatorComponent={this.renderListSeparator}
                    ListFooterComponent={this.renderListFooter}
                    renderItem={({ item }) =>
                        <TouchableOpacity onPress={() => {
                            this.props.navigation.navigate('ProductDetails', {
                                productId: item.id,
                                productName: item.name,
                                base_url: this.state.base_url,
                                c_key: this.state.c_key,
                                c_secret: this.state.c_secret
                            });
                        }}>
                            <View style={{ flex: 1, flexDirection: 'row', backgroundColor: 'white' }}>
                                <View style={{ flex: 1, justifyContent: "center", alignContent: "center" }}>
                                    <Image source={(Array.isArray(item.images) && item.images.length) ?
                                        { uri: item.images[0].src } :
                                        require('../../../assets/images/blank_product.png')}
                                        onError={(e) => { this.props.source = require('../../../assets/images/blank_product.png') }}
                                        style={{ height: 115, width: 115 }} resizeMode='contain' />
                                </View>
                                <View style={{ flex: 2, marginTop: 10, marginBottom: 10, justifyContent: "center" }}>
                                    <View style={{ marginLeft: 10 }}>
                                        <Text style={styles.titleText}>{item.name}</Text>
                                        <Text>SKU: {item.sku}</Text>
                                        <Text>Price: {item.price}</Text>
                                        <Text>Stock Status:  {item.stock_status}</Text>
                                        <Text>Stock: {item.stock_quantity}</Text>
                                        <Text>Status: {item.status}</Text>
                                    </View>
                                </View>
                            </View>
                        </TouchableOpacity>
                    }
                />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    titleText: {
        fontSize: 20,
        fontWeight: 'bold',
    }
});

您可以添加默认为 true 的状态属性hasMoreToLoad

然后您可以检查fetchProductList如果结果小于per_page (data < 20) 如果结果小于per_page你知道你已经到了最后,你可以将hasMoreToLoad设置为 false。

onEndReached={this.state.hasMoreToLoad ? this.handleLoadMore : null}

只需简单地将条件放在onEndReached()

<FlatList
  data={this.state.data}
  keyExtractor={item => item.id.toString()}
  refreshing={this.state.refreshing}
  extraData={this.state.data}
  onRefresh={this.handleRefresh} 
  onEndReached={this.status.data.length > 0 ? this.handleLoadMore : null} // change here
  ...
  ...
/>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM