Reactjs React Native:当从rest api返回空json数组时,停止平面列表的onEndReached的Endless循环
我正在使用互联网上提到的react native的无限滚动平面列表模式。到目前为止,它有利于长数据。但是当RESTAPI分页完成时,它返回空的JSON数组。现在使用无限滚动模式,onEndReached函数被无限抛出,导致不必要的rest调用。那么,处理这种情况的最佳方法是什么呢 来自API的数据可以是一行或500行JSON对象,具体取决于代码中提到的条件URL。在500行的情况下,在有更多数据要获取之前是可以的,但是在最后480-500批之后,它变成了一个无限循环,这是一个问题。在一行的情况下,它立即成为一个无止境的循环。我如何有条件地中断onEndReached事件,以便在从RESTAPI检测到空数组时它永远不会触发 下面是我的平面列表实现:Reactjs React Native:当从rest api返回空json数组时,停止平面列表的onEndReached的Endless循环,reactjs,rest,react-native,react-native-flatlist,woocommerce-rest-api,Reactjs,Rest,React Native,React Native Flatlist,Woocommerce Rest Api,我正在使用互联网上提到的react native的无限滚动平面列表模式。到目前为止,它有利于长数据。但是当RESTAPI分页完成时,它返回空的JSON数组。现在使用无限滚动模式,onEndReached函数被无限抛出,导致不必要的rest调用。那么,处理这种情况的最佳方法是什么呢 来自API的数据可以是一行或500行JSON对象,具体取决于代码中提到的条件URL。在500行的情况下,在有更多数据要获取之前是可以的,但是在最后480-500批之后,它变成了一个无限循环,这是一个问题。在一行的情况下
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',
}
});
import React,{Component}来自'React';
从“react native”导入{样式表、文本、视图、平面列表、图像、ActivityIndicator、TouchableOpacity、ToastAndroid};
从“世博安全商店”导入*作为安全商店;
从“/productglobal”导入全局
从“@expo/vector icons”导入{Ionicons};
从“../commoncomponents/SearchBar”导入搜索栏
导出默认类ProductsList扩展组件{
静态导航选项=({navigation})=>{
返回{
标题:“产品”,
头灯:()=>(
{navigation.navigate(“设置”)}
>
),
}
};
建造师(道具){
超级(道具);
此.state={
加载:false,
搜索值:“”,
数据:[],
页码:1,
错误:null,
刷新:错,
基本url:null,
c_键:空,
c_秘密:空,
};
GLOBAL.productlistScreen=这个;
}
异步组件didmount(){
等待此消息。getCredentials();
this.fetchProductList();
}
getCredentials=async()=>{
const credentials=wait SecureStore.getItemAsync('credentials');
const credentialsJson=JSON.parse(凭证)
这是我的国家({
base\u url:credentialsJson.base\u url,
c_key:credentialsJson.c_key,
c_secret:credentialsJson.c_secret,
})
}
fetchProductList=()=>{
const{base_url,c_key,c_secret,page,searchValue}=this.state;
让url=null
如果(搜索值){
url=`${base\u url}/wp json/wc/v3/products?per\u page=20&search=${searchValue}&page=${page}&consumer\u key=${c\u key}&consumer\u secret=${c\u secret};
}否则{
url=`${base\u url}/wp json/wc/v3/products?per\u page=20&page=${page}&consumer\u key=${c\u key}&consumer\u secret=${c\u secret}`;
}
console.log(url)
this.setState({loading:true});
设置超时(()=>{
fetch(url).then((response)=>response.json())
.然后((responseJson)=>{
这是我的国家({
数据:this.state.data.concat(responseJson),
错误:responseJson.code | | null,
加载:false,
刷新:错误
});
}).catch((错误)=>{
这是我的国家({
错误,
加载:false,
刷新:错误
})
});
}, 1500);
};
renderListSeparator=()=>{
返回(
)
}
renderListFooter=()=>{
如果(!this.state.loading)返回null;
返回(
)
}
handleRefresh=()=>{
这是我的国家({
页码:1,
令人耳目一新:是的,
数据:[]
}, () => {
this.fetchProductList();
}
)
}
handleLoadMore=()=>{
console.log('加载已触发')
这是我的国家({
第页:this.state.page+1,
}, () => {
this.fetchProductList();
})
}
handleSearch=(值)=>{
//console.log(值)
这是我的国家({
searchValue:value,
页码:1,
令人耳目一新:是的,
数据:[]
}, () => {
this.fetchProductList()
})
}
render(){
返回(
item.id.toString()}
刷新={this.state.refreshing}
extraData={this.state.data}
onRefresh={this.handleRefresh}
onEndReached={this.handleLoadMore}
onEndReachedThreshold={0.5}
ItemSeparatorComponent={this.renderListSeparator}
ListFooterComponent={this.renderListFooter}
renderItem={({item})=>
{
this.props.navigation.navigate('ProductDetails'{
productId:item.id,
productName:item.name,
base\u url:this.state.base\u url,
c_key:this.state.c_key,
c_秘密:这是国家c_秘密
});
}}>
{this.props.source=require('../../../assets/images/blank_product.png')}
style={{高度:115,宽度:115}}resizeMode='contain'/>
onEndReached={this.state.hasMoreToLoad ? this.handleLoadMore : null}