FlatList does not scrolls down but retracts back to top - react-native

After scrolling, flatlist goes back to the top. Any obvious reason this might be happening because of my code?
react-native-cli: 2.0.1
react-native: 0.57.4
FlatList Code
return (
<View style={{ flex: 1}}>
<FlatList
data={this.state.dataSource}
onEndReached = {() => this.getDeals()}
ListHeaderComponent = {() => <MainAdvertisement/>}
onEndReachedThreshold={1}
renderItem={this._renderItem}
ListFooterComponent={()=>((this.state.loading || this.state.loading=="")&&!this.state.gotAllDeals) ? <ActivityIndicator size="small" color="gray"/> : null}
keyExtractor={(item, index) => item._id}
/>
</View>
);
getDeals()
This is the function called when end of Flatlist is reached.
getDeals = () => {
this.setState({
loading: true,
});
let url = this.state.url;
let offsetEncoded = encodeURIComponent(this.state.offset);
url=url+"offSet="+offsetEncoded+"&&filters="+JSON.stringify(this.props.filters);
console.log(url);
fetch(url)
.then((res)=>{
if (!res.ok) {
throw Error(res.statusText);
}
return res;
})
.then((res) => res.json())
.then((responseJson) => {
if(responseJson.length==0){
this.setState({
gotAllDeals:true,
loading:false
})
}
else{
this.setState({
loading: false,
dataSource: this.state.offset==0 ? responseJson : [...this.state.dataSource, ...responseJson],
offset: this.state.offset + responseJson.length,
dealList_ErrorStatus: false
});
}
})
.catch((err) => {
this.setState({
dealList_ErrorStatus: true,
loading:false
})
console.log("Error: "+err);
});
}
ScreenRecording

Related

Warning: Each child in a list should have a unique "key" prop. React Native

Hello i'm trying to build a mini social media app with react native, getting the following error:
Warning: Each child in a list should have a unique "key" prop.
Check the render method of VirtualizedList
tried to use results.map instead of flat list also.
and also to change the key extractor with solutions on stackoverflow, but no success.
anyone can help please ?
code:
return (
<FlatList
style={{flex:1}}
data={results}
keyExtractor={(item, index) => {
return item.id;
}}
renderItem={({item}) => <TouristCard key={item.id} item={item} onPress={()=> navigation.navigate('HomeProfile', {userId: item.userId})} /> }
/>
);
TouristCard:
const TouristCard = ({item,onPress}) => {
return (
<View key={item.id} style={styles.listItem} >
<UserImg source={{uri: item.userImg ? item.userImg : 'https://lh5.googleusercontent.com/-b0PKyNuQv5s/AAAAAAAAAAI/AAAAAAAAAAA/AMZuuclxAM4M1SCBGAO7Rp-QP6zgBEUkOQ/s96-c/photo.jpg'}}/>
<View style={{alignItems:"center",flex:1}}>
<Text style={{fontWeight:"bold"}}>{item.fname ? item.fname : 'Annonymous' } {item.lname ? item.lname : '' }</Text>
<Text>{item.flightDesc}</Text>
<Text style={{fontWeight:"bold"}}>{item.age}</Text>
</View>
<Text style={{color:"blue"}}>View Profile</Text>
</View>
);
results object:
const filterByDates = (results,startDate,endDate) => {
return results.filter(res => {
return startDate<res.endDate && res.startDate<endDate;
});
};
useEffect(() => {
const fetchCommunity = async() => {
try {
//const list = [];
await firestore()
.collection('flights')
.where("destination","==",destination)
.where("user","!=",user.uid)
.get()
.then((querySnapShot) => {
querySnapShot.forEach(doc => {
const {user,flightDesc,startDate,endDate} = doc.data();
list.push({
user: user,
flightDesc,
startDate,
endDate
});
})
})
setResults(filterByDates(list,startDate,endDate));
fetchProfiles();
} catch(e) {
console.log(e);
}
}
const fetchProfiles = async() => {
try {
//const list2=[];
list.forEach(async obj => {
await firestore()
.collection('users')
.where("userId","==",obj.user)
.get()
.then((querySnapShot) => {
querySnapShot.forEach(doc => {
const {userImg,age,fname,lname} = doc.data();
list.push({
id: doc.id,
userImg,
age,
fname,
lname
});
})
})
setResults(list);
console.log(list);
})
} catch (e) {
console.log(e);
}
}
fetchCommunity();
},[]);
Replace your Flatlist with this.
<FlatList
style={{flex:1}}
data={results}
keyExtractor={(item) => item.id.toString()} // Here was the error
renderItem={({item}) => <TouristCard item={item} onPress={()=> navigation.navigate('HomeProfile', {userId: item.userId})} /> }
/>
Also check whether each element of your results has a unique id or not?
And MAIN point... Check does your array items has a property called id or not..and if userId is unique then use that as shown above

Trying to get result from more than one api React native in the same page

i m trying to get data from database and put it inside a picker when i use one fecth it work fine but when i add the second one it get an error says " typeError: undefined is not an object (evaluating 'this.state.dataSource2.map') "
componentDidMount() {
fetch('url1')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson,
}
);
})
.then( () => {
fetch('url2')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource2: responseJson
});
})
})
.catch((error) => {
console.error(error);
});
}
first picker :
onValueChange={(itemValue, itemIndex) => this.setState({ar1: itemValue})} >
{ this.state.dataSource.map((item, key)=>(
<Picker.Item label={item.nom} value={item.nom} key={key} />)
)}
</Picker>
second picker :
onValueChange={(itemValue, itemIndex) => this.setState({ar2: itemValue})} >
{ this.state.dataSource2.map((item, key)=>(
<Picker.Item label={item.nom} value={item.nom} key={key} />)
)}
</Picker>

How to display fetched data in react native

I successfully posted data in MongoDB Atlas, Now i want to display that data in my simple react native App. Data is showing in my terminal but i am not able to display data in my App.
Here is code for Get data form the db.
display(){
fetch('myUrl', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
title: responseJson,
description: responseJson
})
})
.catch((error) => {
console.error(error);
});
}
Here is the code that is not displaying the data in App
<TouchableOpacity onPress={()=>this.display()} style={styles.btn}>
<Text style={{textAlign: 'center'}}> Display </Text>
</TouchableOpacity>
<View>
<FlatList
data={this.state.title}
renderItem={({item}) => <Text>{item.title}</Text>}
keyExtractor={({id}, index) => id}
/>
</View>
Flatlist data property expects an array.
But you seem to set an object.
If your api returns an array you can make the following changes to make it work:
state = {
items:[]
}
display() {
fetch('myUrl', { method: 'GET'})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
items: responseJson
})
})
.catch((error) => {
console.error(error);
});
}
As you see I used items in state as array, and updated its value when I got response from api.
And in flatlist:
<View>
<FlatList
data={this.state.items}
renderItem={({item}) => <Text key={item._id}>{item.title}</Text>}
keyExtractor={ item => item._id}
/>
</View>
A sample codesandbox
Update your code like this:
this.state = {
responseData:[]
}
display = () => {
fetch('myUrl', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
responseData: responseJson,
})
})
.catch((error) => {
console.error(error);
});
}
inside your render function:
render(){
const { responseData } = this.state;
return(
<TouchableOpacity onPress={()=>this.display} style={styles.btn}>
<Text style={{textAlign: 'center'}}> Display </Text>
</TouchableOpacity>
<View>
<FlatList
data={responseData}
renderItem={this.renderItem}
keyExtractor={item => item.id}
/>
</View>
);
}
renderItem = ({item}) => {
const { title, id, description, date } = item;
<View key={item.id}>
<Text>{item.id}</Text>
<Text>{item.title}</Text>
<Text>{item.description}</Text>
<Text>{item.date}</Text>
</View>
}
try with return keywork
Working demo api
display(){
return fetch('myUrl', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
title: responseJson,
description: responseJson
})
})
.catch((error) => {
console.error(error);
});
}

Refresh data in react-native

Hi so I want to refresh data when I pull down but I'm not sure about how to do it. Here is my code :
async componentDidMount() {
this.getData();
}
async getData(){
const url = "SomeUrl";
await fetch(url)
.then(res => res.json())
.then(res => {
this.setState({
dataSource: res
});
})
.catch(error => {
console.log("get data error:" + error);
});
}
<SafeAreaView style={{ flex:1 }}>
<View style={styles.main_container}>
<FlatList style={styles.flatList}
data={this.state.dataSource}
extraData = {this.state}
keyExtractor={(item, index) => item.MembreId}
renderItem={(item) => <UserItem user={item} displayDetailForUser={this._displayDetailForUser} />}
numColumns={numColumns}
refreshing={this.state.refreshing}
onRefresh={this.handleRefresh} />
</View>
</SafeAreaView>
So here I'm getting the data in dataSource. I have tried this but it's loading endlessly.. And do I also need to wipe the previous data in dataSource first or not ?
handleRefresh = () => {
this.setState (
{
refreshing: true,
},
() => {
setTimeout(() => {this.getData()}, 1000)
}
);
};
It looks like you are not setting the refreshing back to false once the data comes back. Try this for getData:
async getData(){
const url = "SomeUrl";
await fetch(url)
.then(res => res.json())
.then(res => {
this.setState({
dataSource: res,
refreshing: false,
});
})
.catch(error => {
console.log("get data error:" + error);
});
}
Try setting refreshing state to false in this.getData() with dataSource.

How to refresh a single item in a FlatList in React-Native?

I made a Like function with React and Flask API, it works pretty well, it makes the Like action but it only appears when I refresh the whole list. Somehow I want to refresh the Like picture and the Like count at the post.
I tried to put extraData in my FlatList but that does not solve my problem...
handleClick() {
const headers = {
'Authorization': 'jwt ' + this.props.jwt
};
const action = this.props.has_liked? 'unlike':'like'
axios.post("http://127.0.0.1:5000/API/likeaction",{
id: this.props.id,
action: action
}, {
headers: headers
})
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error)
});
this.setState({liked: action})
}
render() {
const img = this.props.has_liked? require('../assets/icons/heart-filled.png') : require('../assets/icons/heart-no-fill.png')
return(
<View style={{flex:1, marginTop: 10, marginBottom:16, left: 20}}>
<View style={{flex: 1, flexDirection: 'row'}}>
<Image source={this.props.image_uri} style={{height:42, width: 42, borderRadius:21}}/>
<Text style={{left:20,paddingTop:6}}>{this.props.author}</Text>
<Text style={{position: 'absolute', right: 40, paddingTop:6,fontSize:12,color:'#babbbc'}}> {this.props.date} </Text>
</View>
<View style={{flex:1, left: 60, right:20,width: '70%', marginTop:-10}}>
<Text style={{fontWeight:'bold',fontSize:18,marginBottom:6}}>{this.props.title} </Text>
<Text style={{fontSize:16,marginBottom:6 }}>{this.props.content}</Text>
<View style={{flex: 1, flexDirection: 'row'}}>
<TouchableOpacity onPress={this.handleClick}>
<Image style={{width:24, height:24, marginBottom:6, marginTop:6}} source={img} />
</TouchableOpacity>
<Text style={{paddingTop:10, marginLeft:6, fontSize:14,color:'#bfbfbf'}}>{this.props.likes}</Text>
</View>
</View>
</View>
);
}
}
<FlatList
data={this.state.dataSource}
extraData={this.state}
renderItem={({item}) => <PostView title={item.title}
content={item.content}
author={item.author}
date={item.date_posted}
likes={item.likes}
has_liked={item.has_liked}
jwt = {this.props.screenProps.jwt}
id = {item.id}
image_uri={{uri:'http://127.0.0.1:5000/static/profile_pics/'+item.profile_image}}/> }
refreshing={this.state.refreshing}
onRefresh={this.handleRefresh}
keyExtractor={item => item.id}/>
</View>
extraData :
extraData={{this.state}}
and put this.setState({liked: action}) here:
.then((response) => {
console.log(response.data);
this.setState({liked: action})
})
try with in home
this.state = {
loading: true,
email: '',
error: '',
refreshing: false,
dataSource: [],
updated: false
}
handleChange = () => {
this.setState({ updated: true })
}
handleRefresh = () => {
this.setState({
refreshing: true,
data: this.state.dataSource
}, () => {
this.makeRemoteRequest()
})
}
Replace
<PostView title={item.title}
....
/>
with
<PostView title={item.title}
.....
handleChange={this.handleChange}/>
extraData={this.state}
and update
and
handleClick() {
const headers = {
'Authorization': 'jwt ' + this.props.jwt
};
axios.post("http://127.0.0.1:5000/API/likeaction",{
id: this.props.id,
}, {
headers: headers
})
.then((response) => {
console.log(response.data);
if(response.data.account == "liked"){
this.setState({liked:true})
}else{
this.setState({liked:false})
}
})
.catch((error) => {
console.log(error)
});
}
with
handleClick() {
const headers = {
'Authorization': 'jwt ' + this.props.jwt
};
axios.post("http://127.0.0.1:5000/API/likeaction",{
id: this.props.id,
}, {
headers: headers
})
.then((response) => {
console.log(response.data);
this.props.handleChange(true);
if(response.data.account == "liked"){
this.setState({liked:true})
}else{
this.setState({liked:false})
}
})
.catch((error) => {
console.log(error)
});
}
const img = this.state.liked? require('../assets/icons/heart-filled.png') : require('../assets/icons/heart-no-fill.png')
with
const img = this.state.liked ? require('../assets/icons/heart-filled.png') : require('../assets/icons/heart-no-fill.png')