I'm new to react native and my english is so-so and i couldn't find solution to my problem. My goal is to, once fetched a json array, to give the component the onPress navigator function so that, by clicking on the chosen item, it can send me back to a second page with the data of the array value.
export default class Brewery extends React.Component{
state ={
breweries: []
}
async componentDidMount(){
let url='https://jsonplaceholder.typicode.com/photos'
fetch(url)
.then((response) => response.json())
.then((json) =>{
console.log('JSON' , json)
this.setState({breweries: json})
})
.catch((error) => {
console.error(error);
this.setState({breweries:[]})
});
}
render(){
return(
<FlatList
numColumns={2}
data={this.state.breweries}
renderItem={({ item }) => (
<View style={styleSingleResult.box}>
<Image style={styleSingleResult.logo}
source={{uri: item.thumbnailUrl}} />
<Text>{item.title}</Text>
</View>
)}
ListEmptyComponent={() =>
<View>
<Text>NSE Ciae DIOLADRO</Text>
</View>}
/>
)
}
}
I thought I would use
<TouchableOpacity onPress={() => navigation.navigate('NextPage', item)}>
and in the destination page the get:
<Text>{navigation.getParam('title')}</Text>
To recall the value of the item. Except that in the Brewery class I can't implement the "navigation" method .. How can I solve?
I read your requirement, So the solution is create a component name it for example:
<SecondScreen data={breweries} />
And when component mounted you can access data if exists or fetched well from server without any error.
I hope help you with my poor explaining
Related
I am using react native with laravel back end so i just want to load list from laravel so for that i code like that
constructor() {
super();
this.state = {
data:[
{
student_name: '',
class:'',
section:'',
},
],
}
//id is also in state and i get it's value from async storage
fetch('http://192.1.1.:8000/api/students/' + this.state.id, {
method: 'get',
})
.then((response) => response.json())
.then((responseJson) => {
if (responseJson.message === 'success') {
responseJson.data.map((userData) => {
this.setState({student_name: userData.student_name})
this.setState({class: userData.class})
this.setState({section: userData.section})
});
}
that's how i get record from laravel and update state in react native. but when i use flat list in react native it throw me that error
VirtualizedList: missing keys for items, make sure to specify a key or id property on each item or provide a custom keyExtractor.
My react native view is like that
<View>
<Text style={{fontSize:50}}>FlatList</Text>
<FlatList
data={this.state.data}
renderItem={({item})=><Text style={{fontSize:50}}>{item.student_name}</Text>}
/>
</View>
Can you try this?
keyExtractor={(item, index) => index.toString()}
You have to add a unique key (or id) prop for Text element in FlatList.
Supposing that your this.state.data items have an id, you could write something like:
<View>
<Text style={{fontSize:50}}>FlatList</Text>
<FlatList
data={this.state.data}
renderItem={({item})=><Text key={item.id} style={{fontSize:50}}>{item.student_name}</Text>}
/>
</View>
Alternatively, you could add keyExtractor to FlatList in this way:
<View>
<Text style={{fontSize:50}}>FlatList</Text>
<FlatList
data={this.state.data}
renderItem={({item})=><Text style={{fontSize:50}}>{item.student_name}</Text>}
keyExtractor={(item) => item.id}
/>
</View>
in Flatlist you have been need on key parameter . you must get that from list , like id parameter .
add this parameter to flatlist item
style={styles.flatListStyle}
data={this.state.bestSuggester}
key={item => item.Rank}
Its because you are missing keyExtractor
Replace your code with this:
<View>
<Text style={{fontSize:50}}>FlatList</Text>
<FlatList
data={this.state.data}
keyExtractor={(item, index) => String(index)}
renderItem={({item})=><Text style={{fontSize:50}}>{item.student_name}</Text>}
/>
</View>
So, I recently started making FlatList a recurring thing in the app I'm working on. I am right now working on a screen that gives a list of requests and is updated once one is accepted, which is done by pressing a button. There's a method called getNewRequests I am using to update the requests, but it can't seem to be called by the flatline, as it only returns the error TypeError: _this3 is undefined.
I really need that method to work, because I need to update the state of that screen, and trying to type the whole method there only returns the same error. In that context, this always returns undefined.
render(){
return(
<View style={GenericStyles.styles.genericContainer}>
<Text> REQUEST SCREEN </Text>
<FlatList
data={this.state.requestList}
renderItem={this.renderItem}
keyExtractor={item => item.id}
/>
<Button title="Voltar" color="cyan" onPress={() => this.props.navigation.goBack()}/>
</View>
);
}
renderItem({item}){
return(
<Card
containerStyle={{flex: 1, width: 200}}
title={item.Username}>
<Button color="blue" title="Accept" onPress={() => RequestService.allowRequest(item.id, (response) => {
let rsp = JSON.parse(response);
if(rsp.success){
this.getNewRequests();
}
})}/>
</Card>
);
}
You need to either bind the function in your constructor (or wherever you want) doing:
constructor(props){
super(props)
this.renderItem.bind(this)
}
or use arrow function:
renderItem = ({item}) => {
//your function
}
Doing this will give the function access to the this of the current component.
I'm trying to fetch data from API, using the link combined from link fetched from another component and API token, but the API is not returning anything.
I suspect the connection to API might be correct and the issue lies with wrongly fetching specific objects from the API structure. api structure
componentDidMount(){
const { navigation } = this.props;
const linkPlant = navigation.getParam('linkPlant');
fetch(linkPlant + '?token=/////FY03yEVzS77Ca1Q9TIbMdMlJhXtpOjhcqcD-MJHA')
.then(response => response.json())
.then((responseJson)=> {
this.setState({
loading: false,
dataSource: responseJson
})
})
.catch(error=>console.log(error))
}
renderItem=(data)=>
<TouchableOpacity style={styles.list}>
<Text style={styles.lightText}>{data.item.varieties[0].common_name}</Text>
</TouchableOpacity>
render(){
return(
<View>
<FlatList
data= {this.state.dataSource}
renderItem= {item=> this.renderItem(item)}
keyExtractor= {item=>item.id.toString()} />
</View>
</ScrollView>
);}
{!loading?
<View>
<FlatList
data= {this.state.dataSource}
renderItem= {item=> this.renderItem(item)}
keyExtractor= {item=>item.id.toString()} />
</View>
: <View><Text>Loading</Text></View>}
You've defined an loading promise but never used that. Maybe using it for render when page is loaded could be fix that error.
This a simple FlatList:
class Products ..
render() {
return (
<FlatList
renderItem={this._renderItem}
);
}
I want to create a list of items and navigate to Detail Page by onPress items.
Can Please tell me which method is better?
Method 1:
Insert navigate to Detail page in child component(CardProduct component) like this:
_renderItem = ({item}) => (
<CardProduct
id={item.id}
title={item.title}
/>
);
and in CardProduct component:
render() {
const { id,title } = this.props;
return (
<Card style={{flex:1}}>
<CardItem cardBody button onPress={() => this.props.navigation.navigate('Details',{productId:id})}>
...
);
}
Method 2:
Insert navigate to Detail page in current component(Products component) like this:
_onPressItem = (id: string) => {
this.props.navigation.navigate('Details',{productId:id});
};
_renderItem = ({item}) => (
<CardProduct
id={item.id}
title={item.title}
onPressItem={this._onPressItem}
/>
);
and in CardProduct component:
_onPress = () => {
this.props.onPressItem(this.props.id);
};
render() {
const { id,title } = this.props;
return (
<Card style={{flex:1}}>
<CardItem cardBody button onPress={this._onPress}>
...
);
}
I used to do the method 1, but I read this guide.
Short answer:
You should go for method2.
Explanation:
In method1 you are using an arrow function in CardItem's onPress, so everytime CardProduct is re-rendered a new reference of onPress is created, which forces CardItem to re-render, even if all the other props are staying the same. In method 2 you are binding the function to context, which won't force a re-rendering of the CardItem.
By the way, in general it is a good idea to prevent the usage of arrow functions in render().
One step for performance optimization in react-native flatlist, is using a stateless functional component for the renderItem. and you should always give each item a unique key.
I'm having trouble keeping the data in my Flatlist after coming back from another page. My scenario is as follows:
User goes to homepage and scrolls through 20 items
User clicks their profile tab changing page using react-native-router-flux
User clicks the home tab taking them back to the list however the list re-renders and starts from the top.
How can I stop this re-rendering and fetching the same data again?
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteReuest gets my data from firebase in batches of 5 and sets data: []
data: [...this.state.data, ...results]
I've tried using the below but not sure if this is correct, when i navigate away and back the data re-renders. I want to keep the data so the page will be exactly the same as when it was left.
shouldComponentUpdate(nextProps, nextState) {
if (JSON.stringify(this.state.data) !== JSON.stringify(nextState.data)) {
return true;
}
return false;
}
My flatlist:
<View>
<FlatList
scrollsToTop={false}
ref={(ref) => { this.flatListRef = ref; }}
showsHorizontalScrollIndicator={false}
onScroll={this.handleScroll}
data={this.state.data}
keyExtractor={item => item.key}
ListFooterComponent={this.renderFooter()}
onRefresh={this.handleRefresh}
refreshing={this.state.newRefresh}
onEndReached={this.handleEndRefresh}
onEndReachedThreshold={0.05}
getItemLayout={this.getItemLayout}
renderItem={this.renderItem}
/>
{this.state.refreshAvailable ? this.renderRefreshButton() : null}
</View>
Thanks for any help!
Coded long back for the dumb project, maybe this can help you
The View: used onLayout Prop for getting the y-axis
<ScrollView
ref={(ref) => this.scrollTo = ref}
contentContainerStyle={{margin:5,}}
>
<Card onLayout={(event) => this._findHeight(event.nativeEvent.layout, 'personal')}>
<Personal review={true}/>
</Card>
</ScrollView>
The Function: stored the y-axis; here i have used realm db
_findHeight = (e, name) => {
const {x, y, width, height} = e;
this.realm.write(() => {
this.realm.create('yLocation',{names:name,yaxis:y}) :
});
}
The AutoScroll Method: here i have used scrollTo method from ScrollView you can use any method using their ref
_scrollTo = (y) => {
this.scrollTo.scrollTo({x:0,y:y,animated:true});
}
Note : Call _scrollTo method in componentDidMount