I'm working on React native. I'm using FlatList. I want to show the loading bar as I go down. I wrote the code for that.
I've reviewed the documentation, but it's not working. I guess I'm making a mistake at the await. I don't know how to use it. What is the difference of async? I'm leaving the code sample below.
Thanks in advance for your help.
handleRefresh = () => {
this.setState({
offset: 0,
maxSize: 10,
isSearch: false,
isLoading: true,
isRefreshing: true
}, () => {
this.loadData();
});
};
handleLoadMore = () => {
this.setState({
maxSize: this.state.maxSize + 5,
isSpinner: true
}, () => {
this.loadData();
});
};
keyExtractor = (item, index) => index.toString();
renderFooter = () => {
if(this.state.isSpinner === false) { return null; }
return (
<View style={{ paddingVertical: 20 }}>
<ActivityIndicator animating size="small" />
</View>
);
};
loadData = async () => {
try {
const { offset, maxSize } = this.state;
const username = await AsyncStorage.getItem('username');
const token = await AsyncStorage.getItem('token');
var credentials = Base64.btoa(username + ':' + token);
var URL = `http://demo.espocrm.com/advanced/api/v1/Lead?sortBy=createdAt&asc&offset=${offset}&maxSize=${maxSize}`;
axios.get(URL, {headers : { 'Espo-Authorization' : credentials }})
.then(this.dataSuccess.bind(this))
.catch(this.dataFail.bind(this));
} catch (error) {
Alert.alert(
'Hata',
'Bir hata meydana geldi. Lütfen yöneticiye başvurunuz.',
[
{ text: 'Tamam', onPress: () => null }
]
);
}
};
dataSuccess(response) {
this.setState({ isRefreshing: false, isSpinner: false, isLoading: false, leadList: response.data.list });
}
dataFail(error) {
this.setState({ isLoading: false });
Alert.alert(
'Hata',
'Beklenmedik bir hata oluştu',
[
{ text: 'Tamam', onPress: () => null }
]
);
}
render() {
const { isLoading, isRefreshing, searchText, leadList } = this.state;
return(
<View style={styles.container}>
<SearchBar
placeholder="Bir lead arayın..."
onChangeText={this.searchLead.bind(this)}
onClear={this.handleRefresh}
onCancel={this.loadData}
value={searchText}
/>
{
isLoading ? <ActivityIndicator style={styles.loading} size="large" color="orange" /> :
<FlatList
data={leadList}
ListFooterComponent={this.renderFooter}
renderItem={({item}) =>
<ListItem
leftAvatar={{ source: { uri: 'https://pbs.twimg.com/profile_images/567081964402790401/p7WTZ0Ef_400x400.png' } }}
title={item.name}
subtitle={item.status}
bottomDivider={true}
/>
}
keyExtractor={this.keyExtractor}
refreshing={isRefreshing}
onRefresh={this.handleRefresh}
onEndReached={this.handleLoadMore}
onEndReachedThreshold={0.5}
/>
}
</View>
)
}
}
In your FlatList component, you need to include an attribute called extraData and set that to this.state so the component will update.
<FlatList
data={leadList}
extraData={this.state}
...
/>
Related
I have an flatlist which isn't asynchrone so if i update something in my view i have to go back to the home screen and re-enter to check the modifications or save my project , i have implemented async and await in my fetch but still nothing happens !
Here is my code if someone could help me with this issue i'll appreciate it
class listDépenses extends React.Component{
constructor(props) {
super(props);
this.delayValue = 8000;
this.state = {
search:'',
dataSource: [],
animatedValue: new Animated.Value(0),
Montant:'',
Titre:'',
isLoading:true,
modalVisible:false,
}
this.arrayholder=[]
}
onPresino(item){
this.props.navigation.navigate(
'supprimerDépense',
{item})}
renderSeparator =() => {
return(
<View style={{height:1,width:'100%',backgroundColor:'#ccc'}}>
</View>
)}
renderItem = ({item}) => {
this.delayValue = this.delayValue + 500;
const translateX = this.state.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [this.delayValue,1]
});
return(
<Animated.View
style={[styles.button, { transform: [{ translateX }] }]}
>
<View style={{flex:1,}}>
<View style={{flexDirection:'row',padding:10,flex:1}}>
<Avatar.Image
source={{
uri:uri
size={50}
/>
<Text style={[globalStyles.sousTitre,{marginVertical:10,marginLeft:10}]}>{item.Titre}</Text>
<Text style={[globalStyles.sousTitre,
{marginVertical:10,marginLeft:40,textAlignVertical:'auto',opacity:0.8,fontWeight:'800'}]}>
{item.Montant}
</Text>
<View style={{flex:1,alignItems:'flex-end',marginVertical:10}}>
<TouchableOpacity
onPress={()=> this.onPresino(item)}>
<Image
style={{ marginRight:50}}
source={require('../img/corbeille.png')}
/>
</TouchableOpacity>
</View>
</View>
</View>
</Animated.View>
)}
async componentDidMount() {
Animated.spring(this.state.animatedValue, {
toValue: 1,
tension: 20,
useNativeDriver: true
}).start();
return await fetch('http://localhost:8080/api/depenses')
.then((response )=> response.json())
.then(responseJson => {
this.setState({
dataSource: responseJson,
isLoading: false,},
function() {
this.arrayholder = responseJson;
});})
.catch(error => { console.error(error);
});
}
search = text => { console.log(text);
};
clear = () => { this.search.clear();
};
SearchFilterFunction(text) {
const newData = this.arrayholder.filter(function(item) { const itemData = item.Titre ?
item.Titre.toUpperCase() :
''.toUpperCase();
const textData = text.toUpperCase(); return itemData.indexOf(textData) > -1;
});
this.setState({ dataSource: newData, search: text,
});
}
remove= async ()=>{
const _id=this.props.route.params.item._id;
const apiUrl='http://192.168.1.10:8080/api/depenses';
Alert.alert(
//title
'Confirmez votre choix',
//body
'Voulez-vous vraiment supprimer cet article?',
[
{
text: 'Confirmer',
onPress: () => fetch(apiUrl + "/" + _id, {
method: 'DELETE',
mode:'no-cors',
}).then(() => {
Alert.alert(
"Message de confirmation",
"Dépense supprimée.",
[
{ text: "OK", onPress: () => this.props.navigation.navigate('listDépenses') }
]
); }).catch(err => {
console.error(err)})},
{
text: 'Annuler',
onPress: () => console.log('Cancel'), style: 'cancel'},],
{cancelable: false},
//clicking out side of alert will not cancel);}
render(){
if (this.state.isLoading) { return (
<View style={{ flex: 1, paddingTop: 21 }}>
<ActivityIndicator />
</View>
);
}
return (
<View style={styles.container}>
<SearchBar
round="default"
lightTheme="default"
searchIcon={{ size: 25 }}
onChangeText={text => this.SearchFilterFunction(text)} onClear={text =>
this.SearchFilterFunction('')} placeholder="Tapez ici pour chercher..." value=
{this.state.search}
/>
<View style={{marginBottom:10}}></View>
<FlatList
data={this.state.dataSource}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
enableEmptySections={true} style={{ marginTop: 11 }}
ItemSeparatorComponent={this.renderSeparator}
/>
</View>
)}}
I've found the solution if anyone need it :
You just have to implement a function that reloads data:
displayData(){
return fetch('http://localhost:8080/api/depenses')
.then((response )=> response.json())
.then(responseJson => {
this.setState({
dataSource: responseJson,
isLoading: false,
},
function() {
this.arrayholder = responseJson;
});})
.catch(error => { console.error(error);
});
}
componentDidUpdate()
{
this.displayData()
}
componentDidMount() {
this.getData();
Animated.spring(this.state.animatedValue, {
toValue: 1,
tension: 20,
useNativeDriver: true
}).start();
this.displayData()
}
and this is the function :
getData = async () => {
const apiUrl='http://localhost:8080/api/depenses';
await fetch(apiUrl,{
method:'get',
mode:'no-cors',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
dataSource:responseJson
})
})
.catch((error) =>{
console.log(error)
})
}
I've implemented an searchbar as a header of a flatlist which displays my api data (the flatlist works fine ) but the searchbar don't work , i've tried several codes but stills not working
If someone can help me with this i'll appreciate it :)
My API displays an document which contains :
-Titre(String)
-Montant(Number)
I want to search by Titre .
Here's the last code that i've tried :
class listDépenses extends React.Component{
constructor() {
super();
this.state = {
refreshing: true,
dataSource: [],
Montant:'',
Titre:'',
modalVisible:false,
loading: false,
data: [],
error: null,
}
this.arrayholder = [];
}
renderItem = ({item}) => {
<View style={{flex:1}}>
<Text style={[globalStyles.sousTitre,{marginVertical:10,marginLeft:10}]}>{item.Titre}</Text>
<Text style={[globalStyles.sousTitre,
{marginVertical:10,marginLeft:40,textAlignVertical:'auto',opacity:0.8,fontWeight:'800'}]}>
{item.Montant}</Text>
</View>}
searchFilterFunction = text => {
const newData = this.arrayholder.filter(item => {
const itemData = `${item.Titre.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
renderHeader = () => {
return(
<SearchBar
placeholder="Tapez ici..."
onChangeText={text => this.searchFilterFunction(text)}
round="default"
lightTheme="default"
/>
)
}
this.setState({ data: newData });
};
async componentDidMount() {
await fetch ('http://192.168.1.10:8080/api/depenses',{
method:'get',
mode:'no-cors',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
}})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
dataSource:responseJson,
data: responseJson.results,
loading: false,
})
this.arrayholder = responseJson.results;
})
.catch((error) =>{
console.log(error)
})}
render(){
return (
<View style={{flex:1}}>
<View style={{marginBottom:10}}></View>
<FlatList
data={this.state.dataSource}
renderItem={this.renderItem}
keyExtractor={(item, index) => index}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
/>
</View>
I've found the solution if anyone need it :
class listDépenses extends React.Component{
constructor(props) {
super(props);
this.delayValue = 8000;
this.state = {
search:'',
dataSource: [],
animatedValue: new Animated.Value(0),
Montant:'',
Titre:'',
isLoading:true,
modalVisible:false,
}
this.arrayholder=[]
}
componentDidMount() {
Animated.spring(this.state.animatedValue, {
toValue: 1,
tension: 20,
useNativeDriver: true
}).start();
return fetch('http://localhost:8080/api/depenses')
.then((response )=> response.json())
.then(responseJson => {
this.setState({
dataSource: responseJson,
isLoading: false,
},
function() {
this.arrayholder = responseJson;
});})
.catch(error => { console.error(error);});}
search = text => { console.log(text);
};
clear = () => { this.search.clear();
};
SearchFilterFunction(text) {
const newData = this.arrayholder.filter(function(item) { const itemData = item.Titre
? item.Titre.toUpperCase() :
''.toUpperCase();
const textData = text.toUpperCase(); return itemData.indexOf(textData) > -1;
});
this.setState({ dataSource: newData, search: text,
});
}
render(){
if (this.state.isLoading) { return (
<View style={{ flex: 1, paddingTop: 21 }}>
<ActivityIndicator />
</View>
);
}
return (
<View style={styles.container}>
<SearchBar
round="default"
lightTheme="default"
searchIcon={{ size: 25 }}
onChangeText={text => this.SearchFilterFunction(text)} onClear={text =>
this.SearchFilterFunction('')} placeholder="Tapez ici pour chercher..." value=
{this.state.search}
/>
<View style={{marginBottom:10}}></View>
<FlatList
data={this.state.dataSource}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
enableEmptySections={true} style={{ marginTop: 11 }}
ItemSeparatorComponent={this.renderSeparator}
/>
</View>
export class Diet extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
fullData: [],
loading: false,
error: null,
query: "",
};
}
async componentDidMount() {
this.requestAPIFood();
}
requestAPIFood = _.debounce(() => {
this.setState({ loading: true });
const apiURL =
"https://api.edamam.com/api/food-database/v2/nutrients?app_id=${########}&app_key=${#######}";
fetch(apiURL)
.then((res) => res.json())
.then((resJson) => {
this.setState({
loading: false,
data: resJson,
fullData: resJson,
});
})
.catch((error) => {
this.setState({ error, loading: false });
});
}, 250);
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{ paddingVertical: 20, borderTopWidth: 1, borderColor: "red" }}
>
<ActivityIndicator animating size="large" />
</View>
);
};
_renderItem = ({ item, index }) => {
return (
<TouchableOpacity style={{ height: hp("5%") }}>
<Text style={{ left: wp("1%") }}>{item.food}</Text>
</TouchableOpacity>
);
};
handleSearch = (text) => {
const data = _.filter(this.state.fullData);
this.setState({ data, query: text });
};
render() {
return (
<SearchBar
placeholder="Search Food..."
onChangeText={this.handleSearch}
value={data}
/>
<List >
<FlatList
data={this.state.data}
renderItem={this._renderItem}
keyExtractor={(item, index) => index.toString()}
ListFooterComponent={this.renderFooter}
/>
</List>
Good evening, I'm working on a SearchBar component to search food from the API database of Edamam (this is the link to the documentation: https://developer.edamam.com/food-database-api-docs) and display the result on a FlatList as you can see above, but when I start typing nothing will appear and I really can't seem to find the error.
Please check shared video form understanding my issue
https://drive.google.com/file/d/1GKU07Mv7IjiLnrfps5gWpfMPsMphvRDv/view
I need to Flatlist screen every time empty because this below code every time Flatlist API called and then after change Flatlist data.
App Flow
first screen: shows category
second screen: shows selected category quotes
import { StyleSheet,Button,View, Text,FlatList,Dimensions,TouchableHighlight,Clipboard,ToastAndroid,Share,YellowBox } from 'react-native';
import { createAppContainer,NavigationEvents } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { createDrawerNavigator } from 'react-navigation-drawer';
import { createSwitchNavigator } from 'react-navigation-switch-transitioner'
import Icon from 'react-native-vector-icons/Ionicons';
import Style from '../constants/Style';
import Spinner from 'react-native-loading-spinner-overlay';
export default class QuoteActivity extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('Title', 'Default Title'),
headerStyle: {
backgroundColor: navigation.getParam('BackgroundColor', '#5F4B8BFF'),
},
headerTintColor: navigation.getParam('HeaderTintColor', '#fff'),
headerLeft: (
<Icon
style={{ paddingLeft: 15,paddingTop: 5,color:'#FFFFFF' }}
onPress={() => navigation.goBack(null)}
name="ios-arrow-back"
size={40}
/>
)
};
};
constructor(props) {
super(props);
YellowBox.ignoreWarnings([
'Warning: componentWillMount is deprecated',
'Warning: componentWillReceiveProps is deprecated',
]);
}
state = {
spinner: false,isLoading: false,
dataSource:[]
}
// ON FOCUS CALL API
componentDidMount() {
this._doApiCall();
}
// API CALL
_doApiCall = () => {
this.setState({
spinner: true,isLoading:true
});
const { navigation } = this.props;
let CategoryId = navigation.getParam('CategoryId');
fetch('API_URL', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
}
}).then((response) => response.json())
.then((responseJson) => {
this.setState({
// SAMPLE JSON
// {
// "data": [
// {
// "Id": "462",
// "CategoryId": "5",
// "Title": "Being 'Single' is My Attitude!"
// },
// {
// "Id": "464",
// "CategoryId": "5",
// "Title": "I never dreamed about success. I worked for it."
// }
// ],
// "success": "1",
// "message": "2 Quotes found.",
// "service_time": "0.030284881591797 seconds"
// }
// SAMPLE JSON END
spinner:false,isLoading:false,
dataSource:responseJson.data
})
})
.catch((error) => {
console.error(error);
});
};
// Copy to clipboard
writeToClipboard = async (text) => {
await Clipboard.setString(text);
ToastAndroid.show('Quote copied!', ToastAndroid.SHORT);
};
// Share quotes
shareQuotes = async (text) => {
const result = await Share.share({
message:text.toString()+'\n\n Download app from play store',
});
};
_keyExtractor = (item) => item.id;
// RENDER DATA ITEMS
_renderItem = ({item}) => {
return (
<View style={Style.CategoryTitleList}>
<Text style={Style.CategoryTitle}>{item.Title}</Text>
<View style={[{ flexDirection:'row',justifyContent: 'center',alignItems:'center',textAlign:'center',alignSelf:"center"}]}>
<Icon name="ios-copy" onPress={() => this.writeToClipboard(item.Title)} title="Copy" size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
<Icon name="ios-share" onPress={() => this.shareQuotes(item.Title)} size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
</View>
</View>
)
}
render() {
// RENDER DATA ITEMS INSIDE RENDER FNS
renderItem = ({ item, index }) => {
return (
<View style={Style.CategoryTitleList}>
<Text style={Style.CategoryTitle}>{item.Title}</Text>
<View style={[{ flexDirection:'row',justifyContent: 'center',alignItems:'center',textAlign:'center',alignSelf:"center"}]}>
<Icon name="ios-copy" onPress={() => this.writeToClipboard(item.Title)} title="Copy" size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
<Icon name="ios-share" onPress={() => this.shareQuotes(item.Title)} size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
</View>
</View>
);
};
return (
<View style={Style.QuotesListView}>
<NavigationEvents
onDidFocus={this._doApiCall}
onWillFocus={() => this.setState({spinner: true})}
/>
<FlatList
data={this.state.dataSource}
renderItem={renderItem} // USED INSIDE RENDER FNS
refreshing={this.state.isLoading}
onRefresh={this._doApiCall}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={1000}
initialNumToRender={1}
removeClippedSubviews={false}
keyExtractor={this._keyExtractor}
/>
</View>
);
}
}```
Before doing the API Call you can clean the DataSource array that you have.
// API CALL
_doApiCall = () => {
this.setState({
spinner: true,isLoading:true,
dataSource: []
});
...
You can handle that in 2 different ways.
whenever you call _doApiCall function, change initial value of dataSource as an empty array.
_doApiCall = () => {
this.setState({
spinner: true,
isLoading: true,
dataSource: []
});
}
Using ternary operator, diaplay spinner when data loading & if not diaplay faltlist
{
this.state.isLoading ?
<Show your Spinner /> :
<FlatList
data={this.state.dataSource}
renderItem={renderItem}
refreshing={this.state.isLoading}
onRefresh={this._doApiCall}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={1000}
initialNumToRender={1}
removeClippedSubviews={false}
keyExtractor={this._keyExtractor}
/>
}
Feel free for doubt. hope this helps you.
I am trying to cache the api data and fetch it when there is no internet connection. I am getting the data from cache but I am unable to update the data of cache when there is change of data in the api. Also how to check if there no internet connection and load data from cache? I have implemented as follows:
export default class ViewpagerP extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [], isConnected: true }
}
async componentDidMount() {
const photoStorage = await AsyncStorage.getItem('GalleryPhotos')
console.log(photoStorage);
if (!photoStorage) {
try {
console.log("Null inside")
const photoResp = await axios.get('https://www.kitabjatra.com/api/event')
console.log(photoResp)
const photoData = await JSON.stringify(photoResp.data);
await AsyncStorage.setItem('GalleryPhotos', photoData);
const datas = JSON.parse(await AsyncStorage.getItem('GalleryPhotos'));
this.setState({ data: datas, isLoading: false })
} catch (e) {
console.warn("fetch Error: ", error)
}
} else {
this.getPhotos();
}
}
getPhotos = async () => {
try {
data = JSON.parse(await AsyncStorage.getItem('GalleryPhotos'));
this.setState({ data: data, isLoading: false })
console.log(data);
}
catch (error) {
console.error(error);
}
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
)
}
return (
<View style={styles.container}>
<ImageSlider style={styles.viewPagerStyle}
loopBothSides
autoPlayWithInterval={3000}
images={this.state.data}
customSlide={({ index, item, style, width }) => (
<View key={index} style={[style, styles.customSlideStyle]}>
<View style={styles.contentContainer}>
<Image source={{ uri: item.image }} style={styles.customImage} />
<View style={styles.textContainerStyle}>
<Text style={styles.textStyle}>{item.event_title}</Text>
</View>
</View>
</View>
)
}
/>
</View>
);
}
}