在滚动时调用 API 的平面列表无法正常工作
Flatlist with calling API on scroll does not work properly
我在 React Native 中使用 Function 组件。
因为我使用 Flatlist 来查看数据。在 FlatList 的 onEndReached
函数上,我调用 API 来获取数据。
我的问题是
- 滚动API 有时调用两次
- 关于所有数据的完成。 ActivityIndicator 显示在
ListFooterComponent
函数中。
你能帮帮我吗?
提前致谢。
这是我的代码:
import React, { useState, useEffect } from "react";
import {
View,
StyleSheet,
ActivityIndicator,
Image,
FlatList,
TouchableHighlight,
} from "react-native";
import MainStyle from "../constants/Style";
import Layout from "../constants/Layout";
import Colors from "../constants/Colors";
import Services from "../Services";
const LIMIT_PER_PAGE = 10;
let fetching = false;
let isSubscribed = true;
let isListEnd = false;
let pageNo = 1;
var sortby = "latest";
let width = Layout.window.width / 2 - 16;
export default function PostListScreen(props) {
const [posts, setPosts] = useState([]);
fetchAllLatestPost = function () {
console.log("fetchAllLatestPost", fetching, isListEnd);
if (!fetching && !isListEnd) {
fetching = true;
Services.getAllPost(sortby, pageNo, LIMIT_PER_PAGE)
.then(function (res) {
if (!!res) {
console.log("res.length", res.length)
if (!!res.length && isSubscribed) {
pageNo++;
setPosts((posts) => {
posts = [...posts, ...res];
return posts;
});
} else {
isListEnd = true;
}
fetching = false;
}
});
}
};
useEffect(() => {
fetching = false;
isListEnd = false;
pageNo = 1;
isSubscribed = true;
fetchAllLatestPost();
return () => (isSubscribed = false);
}, []);
let readyImage = function (post) {
if (!!post.urls && !!post.urls.regular) {
return typeof post.urls.regular === "string"
? { uri: post.urls.regular }
: post.urls.regular;
} else {
return require("../assets/images/logo_white.png");
}
};
let renderItem = function (post, index) {
return (
<TouchableHighlight onPress={() => onPressPost(post)} key={index}>
<View style={styles.item}>
<Image
source={readyImage(post)}
style={{
flex: 1,
width: null,
height: null,
resizeMode: "cover",
borderRadius: 4,
}}
/>
</View>
</TouchableHighlight>
);
};
let renderFooter = function () {
return (
<View style={styles.footer}>
{console.log("fetching in footer ", fetching)}
{!!fetching ? (
<ActivityIndicator color="white" style={{ margin: 15 }} />
) : null}
</View>
);
};
return (
<View style={MainStyle.wrapper}>
<FlatList
numColumns={2}
keyExtractor={(item, index) => index.toString()}
data={posts}
onEndReached={() => fetchAllLatestPost()}
onEndReachedThreshold={0.5}
renderItem={({ item, index }) => <View>{renderItem(item, index)}</View>}
getItemLayout={(data, index) => ({
length: width,
offset: (width/2) * index,
index,
})}
ListFooterComponent={renderFooter()}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: "row",
flexWrap: "wrap",
},
item: {
height: width,
width: width,
margin: 8,
},
footer: {
padding: 10,
justifyContent: "center",
alignItems: "center",
flexDirection: "row",
},
});
我是这样处理的
<FlatList
data={this.state.posts}
onRefresh={() => {
if (!this.props.posts.fetching) {
this.setState({
page: 1,
checkData: true,
posts: [],
});
this.props.postsRequest({page: 1});
}
}}
// onEndReached={}
keyExtractor={item => item.uid}
onMomentumScrollEnd={() => {
if (!this.props.posts.fetching) {
this.props.postsRequest({page: this.state.page + 1});
this.setState({page: this.state.page + 1, checkData: true});
}
}}
onEndReachedThreshold={0}
refreshing={this.props.posts.fetching}
showsVerticalScrollIndicator={false}
contentContainerStyle={{paddingBottom: 50}}
style={{padding: 10, marginVertical: 10}}
renderItem={item => (
<View style={{marginVertical: 5}}>
<Posts post={item.item} navigation={this.props.navigation} />
</View>
)}
/>
我在 React Native 中使用 Function 组件。
因为我使用 Flatlist 来查看数据。在 FlatList 的 onEndReached
函数上,我调用 API 来获取数据。
我的问题是
- 滚动API 有时调用两次
- 关于所有数据的完成。 ActivityIndicator 显示在
ListFooterComponent
函数中。
你能帮帮我吗? 提前致谢。
这是我的代码:
import React, { useState, useEffect } from "react";
import {
View,
StyleSheet,
ActivityIndicator,
Image,
FlatList,
TouchableHighlight,
} from "react-native";
import MainStyle from "../constants/Style";
import Layout from "../constants/Layout";
import Colors from "../constants/Colors";
import Services from "../Services";
const LIMIT_PER_PAGE = 10;
let fetching = false;
let isSubscribed = true;
let isListEnd = false;
let pageNo = 1;
var sortby = "latest";
let width = Layout.window.width / 2 - 16;
export default function PostListScreen(props) {
const [posts, setPosts] = useState([]);
fetchAllLatestPost = function () {
console.log("fetchAllLatestPost", fetching, isListEnd);
if (!fetching && !isListEnd) {
fetching = true;
Services.getAllPost(sortby, pageNo, LIMIT_PER_PAGE)
.then(function (res) {
if (!!res) {
console.log("res.length", res.length)
if (!!res.length && isSubscribed) {
pageNo++;
setPosts((posts) => {
posts = [...posts, ...res];
return posts;
});
} else {
isListEnd = true;
}
fetching = false;
}
});
}
};
useEffect(() => {
fetching = false;
isListEnd = false;
pageNo = 1;
isSubscribed = true;
fetchAllLatestPost();
return () => (isSubscribed = false);
}, []);
let readyImage = function (post) {
if (!!post.urls && !!post.urls.regular) {
return typeof post.urls.regular === "string"
? { uri: post.urls.regular }
: post.urls.regular;
} else {
return require("../assets/images/logo_white.png");
}
};
let renderItem = function (post, index) {
return (
<TouchableHighlight onPress={() => onPressPost(post)} key={index}>
<View style={styles.item}>
<Image
source={readyImage(post)}
style={{
flex: 1,
width: null,
height: null,
resizeMode: "cover",
borderRadius: 4,
}}
/>
</View>
</TouchableHighlight>
);
};
let renderFooter = function () {
return (
<View style={styles.footer}>
{console.log("fetching in footer ", fetching)}
{!!fetching ? (
<ActivityIndicator color="white" style={{ margin: 15 }} />
) : null}
</View>
);
};
return (
<View style={MainStyle.wrapper}>
<FlatList
numColumns={2}
keyExtractor={(item, index) => index.toString()}
data={posts}
onEndReached={() => fetchAllLatestPost()}
onEndReachedThreshold={0.5}
renderItem={({ item, index }) => <View>{renderItem(item, index)}</View>}
getItemLayout={(data, index) => ({
length: width,
offset: (width/2) * index,
index,
})}
ListFooterComponent={renderFooter()}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: "row",
flexWrap: "wrap",
},
item: {
height: width,
width: width,
margin: 8,
},
footer: {
padding: 10,
justifyContent: "center",
alignItems: "center",
flexDirection: "row",
},
});
我是这样处理的
<FlatList
data={this.state.posts}
onRefresh={() => {
if (!this.props.posts.fetching) {
this.setState({
page: 1,
checkData: true,
posts: [],
});
this.props.postsRequest({page: 1});
}
}}
// onEndReached={}
keyExtractor={item => item.uid}
onMomentumScrollEnd={() => {
if (!this.props.posts.fetching) {
this.props.postsRequest({page: this.state.page + 1});
this.setState({page: this.state.page + 1, checkData: true});
}
}}
onEndReachedThreshold={0}
refreshing={this.props.posts.fetching}
showsVerticalScrollIndicator={false}
contentContainerStyle={{paddingBottom: 50}}
style={{padding: 10, marginVertical: 10}}
renderItem={item => (
<View style={{marginVertical: 5}}>
<Posts post={item.item} navigation={this.props.navigation} />
</View>
)}
/>