Вы вызываете асинхронную функцию c с таймаутом, пока вы прокручиваете до конца. Это время переопределит ваш следующий код и снова установит загрузку в true. Таким образом, загрузка никогда не будет ложной в этом случае.
} else if (this.state.page === this.state.last_page) {
this.setState({loading: false}, () =>
console.log('if--loading', this.state.loading), // log false!! that's mean a spinner should disapeare
);
}
Вам нужно 2 вещи здесь.
1) Попробуйте установить загрузку в false в вашем блоке catch.
} catch (err) {
console.log('err', err);
this.setState({loading: false});
}
2) Добавьте другое значение в вашем штате isAllDataFetched
с начальным значением false. Установите загрузку в false, когда вы получаете пустые данные от вашего API. Не знаю, как выглядят ваши данные, но сделайте что-то вроде:
getData = async () => {
try {
this.setState({loading: true});
let response = await API.get(`/tracks?page=${this.state.page}`);
let lastPage = response.data.data.items.last_page;
let {
data: {
data: {
items: {data},
},
},
} = response;
// if it's an array
if(data.length === 0) {
this.setState({loading: false, isAllDataFetched: true});
}
//...
} catch (err) {
console.log('err', err);
}
};
И, наконец, в вашем методе handleLoadMore добавьте следующую строку.
handleLoadMore = () => {
if(this.state.isAllDataFetched) return;
Я создал демо для вы. Вы можете следовать этой логике c, чтобы заставить ее работать. Это немного отличается от того, что у вас есть, но я думаю, что это поможет.
Вот код.
import React from 'react';
import {
View, Text, FlatList, ActivityIndicator, SafeAreaView
} from 'react-native';
class App extends React.PureComponent {
state = {
songs: [
{
userId: 1,
id: 1,
title: 'delectus aut autem 1',
completed: false,
},
{
userId: 1,
id: 2,
title: 'delectus aut autem 2',
completed: false,
},
],
loading: false,
page: 3,
totalPage: 10,
};
componentDidMount() {
this.getData();
}
getData = async () => {
const { songs } = this.state;
try {
this.setState({ loading: true });
const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${this.state.page}`, {
headers: {
'Content-Type': 'application/json',
},
});
const json = await response.json();
this.setState({
songs: [...songs, json],
});
this.setState({ loading: false });
} catch (err) {
console.log('err', err);
this.setState({ loading: false });
}
};
renderItems = ({ item }) => (
<Text style={{ backgroundColor: 'blue', height: 200, marginBottom: 5 }}>{`${item.title}-${item.id}`}</Text>
);
onEndReached = () => {
const { page, loading, totalPage } = this.state;
if (loading) return;
if (page <= totalPage) {
this.setState({ loading: true, page: page + 1 }, () =>
setTimeout(() => {
this.getData();
}, 2000));
} else {
this.setState({ loading: false });
}
}
renderFooter = () => {
const { loading } = this.state;
if (loading) {
return (
<View>
<ActivityIndicator color="#000" size="large" />
</View>
);
}
return null;
}
renderListEmptyComponent = () => <View />;
render() {
const { songs } = this.state;
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'red' }}>
<FlatList
data={songs}
keyExtractor={song => song.id}
initialNumToRender={10}
contentContainerStyle={{ flexFrow: 1, backgroundColor: 'white' }}
style={{ flex: 1 }}
ListEmptyComponent={this.renderListEmptyComponent}
renderItem={this.renderItems}
onEndReached={this.onEndReached}
onEndReachedThreshold={0.7}
ListFooterComponent={this.renderFooter}
/>
</SafeAreaView>
);
}
}
export default App;
И рабочая демоверсия доступна здесь (используйте устройство iOS)