I am trying to display the zomato restaurant collection of a city on react native page. I am using zomato API. On zomato API documentation, I am using request URL given under "get zomato collections in a city"
Below is my code:
import React from 'react';
import { StyleSheet, Text, View, FlatList, Image, ActivityIndicator } from 'react-native';
import { Card, CardItem } from "native-base"
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: [],
}
}
getUserFromApi = () => {
return (
fetch("https://developers.zomato.com/api/v2.1/collections?city_id=1", {
headers: {
'Content-Type': 'application/json',
'user-key': '2bf4669cad5a8230fd2b220a2d4a37b9'
}
})
.then(response => response.json())
.then(responseJson => {
this.setState({
isLoading: false,
dataSource: responseJson.collections.collection
})
})
.catch(error => console.log(error))
)
}
componentDidMount() {
this.getUserFromApi();
}
render() {
if (this.state.isLoading) {
return (
<View style={styles.progress}>
<ActivityIndicator
size="large"
color="#01CBC6"
/>
</View>
)
}
return (
<View style={{marginTop: 50}}>
<FlatList
data={this.state.dataSource}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<Card>
<CardItem>
<View style={styles.container}>
</View>
<View style={styles.userInfo}>
<Text> collections_id: {item.collections_id}</Text>
</View>
</CardItem>
<CardItem>
<View style={styles.container}>
</View>
<View style={styles.userInfo}>
<Text>title: {item.title}</Text>
</View>
</CardItem>
<CardItem>
<View style={styles.container}>
</View>
<View style={styles.userInfo}>
<Text>description: {item.description}</Text>
</View>
</CardItem>
</Card>
)}
/>
</View>
);
}
}
I am not getting any error, but my screen is blank. There is no output on my screen. I am not able to understand where in my code I am making mistake
//----------------set state like this 👇-----------------------//
this.setState({
isLoading: false,
dataSource: responseJson.collections,
});
//-------------------------------------☝-----------------------//
// Also look FlatList for how the data is rendered //
Working App : Expo Snack
import React from 'react';
import {
StyleSheet,
Text,
View,
FlatList,
Image,
ActivityIndicator,
} from 'react-native';
import { Card, CardItem } from 'native-base';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: [],
};
}
getUserFromApi = () => {
return fetch(
'https://developers.zomato.com/api/v2.1/collections?city_id=1',
{
headers: {
'Content-Type': 'application/json',
'user-key': '2bf4669cad5a8230fd2b220a2d4a37b9',
},
}
)
.then((response) => response.json())
.then((responseJson) => {
console.log('data:', responseJson);
//----------------set state like this------------------------//
this.setState({
isLoading: false,
dataSource: responseJson.collections,
});
//------------------------------------------------------------//
//Also look FlatList for how the data is rendered //
})
.catch((error) => console.log(error));
};
componentDidMount() {
this.getUserFromApi();
}
render() {
if (this.state.isLoading) {
return (
<View style={styles.progress}>
<ActivityIndicator size="large" color="#01CBC6" />
</View>
);
}
return (
<View style={{ marginTop: 50 }}>
<FlatList
data={this.state.dataSource}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<Card>
<CardItem>
<View style={styles.container}></View>
<View style={styles.userInfo}>
{/**access data of for rendering like below 👇 */}
<Text> collections_id: {item.collection.collection_id}</Text>
</View>
</CardItem>
<CardItem>
<View style={styles.container}></View>
<View style={styles.userInfo}>
{/**access data of for rendering like below 👇 */}
<Text>title: {item.collection.title}</Text>
</View>
</CardItem>
<CardItem>
<View style={styles.container}></View>
<View style={styles.userInfo}>
{/**access data of for rendering like below 👇 */}
<Text>description: {item.collection.description}</Text>
</View>
</CardItem>
</Card>
)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: { padding: 10 },
userInfo: { padding: 10 },
});
Related
I made a customized list component (in React Native) which shows touchable images with some description texts.
I need each images open a specific Modal; but I don't know how!! where & how I should code the Modal??
... here is my photo list component:
export class CustomGallery extends Component {
render() {
let {list} = this.props;
return (
<View style={styles.container}>
<FlatList
numColumns={4}
data={list}
renderItem={({ item}) => (
<View style={styles.views}>
<TouchableOpacity style={styles.touch} >
<ImageBackground
style={styles.img}
source={{ uri: item.photo }}
>
<Text style={styles.txt}>{item.name}</Text>
<Text style={styles.txt}>{item.key}</Text>
<Text style={styles.txt}>{item.describtion}</Text>
</ImageBackground>
</TouchableOpacity>
</View>
)}
/>
</View>
);
}
}
For Modal you can use modal from material-ui - https://material-ui.com/components/modal/
The Modal component renders its children node infront of a backdrop component. Simple and basic example would be like a confirmation message that pops up asking whether you surely want to delete particular information or not.
From your code I am guessing you want to display information regarding the image using modal when you click on the image.
Here I have added Modal component:
import React from 'react';
import Modal from '#material-ui/core/Modal';
export class CustomGallery extends Component {
constructor() {
super();
this.state = {
modalOpen: false,
snackOpen: false,
modalDeleteOpen: false,
};
}
handleModalOpen = () => {
this.setState({ modalOpen: true });
}
handleModalClose = () => {
this.setState({ modalOpen: false });
}
render() {
let {list} = this.props;
return (
<View style={styles.container}>
<FlatList
numColumns={4}
data={list}
renderItem={({ item}) => (
<View style={styles.views}>
<TouchableOpacity style={styles.touch} >
<ImageBackground
style={styles.img}
onClick={() => this.handleModalOpen()}
>
{ item.photo }
</ImageBackground>
<Modal
open={this.state.modalOpen}
onClose={this.handleModalClose}
closeAfterTransition
>
<Text style={styles.txt}>{item.name}</Text>
<Text style={styles.txt}>{item.key}</Text>
<Text style={styles.txt}>{item.describtion}</Text>
</Modal>
</TouchableOpacity>
</View>
)}
/>
</View>
);
}
}
I am not sure about how you set the image. But anyways below method is an example of opening modal with dynamic data.
import React, {useState} from "react";
import { Button, TouchableOpacity, FlatList, Modal, Text } from "react-native";
function App() {
const [value, setValue] = useState("");
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
];
return (
<>
<FlatList
data={DATA}
renderItem={({item}) => (
<TouchableOpacity onPress={() => setValue(item.title)}>
<Text>{item.title}</Text>
</TouchableOpacity>
)}
/>
<Modal visible={value}>
<Text>{value}</Text>
<Button title="close" onPress={() => setValue("")} />
</Modal>
</>
)
}
export default App;
I am trying to retrieve data from an API (https://developers.zomato.com/documentation) and get title of restaurants and an image with it. However when I try to load an image I get a warning source.uri should not be an empty string.
Here is my code as it stands:
async componentDidMount() {
let id = this.props.navigation.state.params.category
let result;
try {
result = await axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/search?category=${id}`,
headers: {
'Content-Type': 'application/json',
'user-key': "a31bd76da32396a27b6906bf0ca707a2",
},
})
} catch (err) {
err => console.log(err)
}
this.setState({
isLoading: false,
data: result.data.restaurants
})
}
render() {
return (
<View>
{
this.state.isLoading ?
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator style={{color:'red'}} />
</View> :
(
this.state.data.length == 0 ?
<View style={{ flex: 1, padding: 20 }}>
<Text style={{ color: '#000', fontWeight: 'bold' }}>No restaurants from selected category</Text>
</View> :
<FlatList
style={{ marginBottom: 80 }}
keyExtractor={item => item.id}
data={this.state.data}
renderItem={({ item }) =>
<TouchableHighlight onPress={()=> console.log(item.restaurant.thumb)}>
<Card image={item.restaurant.thumb} style={styles.container}>
<Image resizeMode='contain' source={{ uri: item.restaurant.thumb }}/>
<Text style={{color:'#000',fontWeight:'bold'}}>{item.restaurant.name} </Text>
</Card>
</TouchableHighlight>
}
/>
)
}
</View>
);
}
as you can see when I touch the any of the cards I am console logging the link of the image uri and it shows up perfectly. Why is that when the app loads the images they are empty strings yet when I load it though console log the link shows up perfectly?
I am using axios to load my API
here is an expo snack link: https://snack.expo.io/r1XTaw4JU
So i got 2 issues, one is in the card component you were not providing the uri properly it should be image={{uri:item.restaurant.thumb}} and secondly for newyork your entity id must be
To search for 'Italian' restaurants in 'Manhattan, New York City',
set cuisines = 55, entity_id = 94741 and entity_type = zone
Its as per zomato docs,so do check out that. and find expo link : expo-snack
import React from 'react';
import {
View,
Text,
FlatList,
StyleSheet,
Button,
TouchableHighlight,
ActivityIndicator,
} from 'react-native';
import { createAppContainer } from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import { Card, Image } from 'react-native-elements';
import Constants from 'expo-constants';
import axios from 'axios';
export default class CategoryScreen extends React.Component {
constructor(props){
super(props);
this.state={
data : [],
isVisible: true,
city : '94741'
}
}
async componentDidMount() {
let id = "3"
let city = this.state.city
let result;
try {
result = await axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/search?entity_id=${city}&entity_type=zone&category=${id}`,
headers: {
'Content-Type': 'application/json',
'user-key': "a31bd76da32396a27b6906bf0ca707a2",
},
})
} catch (err) {
err => console.log(err)
}
this.setState({
isLoading: false,
data: result.data.restaurants
})
console.log(result)
console.log(data)
}
render() {
return (
<View>
{
this.state.isLoading ?
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator style={{color:'red'}} />
</View> :
(
this.state.data.length == 0 ?
<View style={{ flex: 1, padding: 20 }}>
<Text style={{ color: '#000', fontWeight: 'bold' }}>No restaurants from selected category</Text>
</View> :
<FlatList
style={{ marginBottom: 80 }}
keyExtractor={item => item.id}
data={this.state.data}
renderItem={({ item }) =>
<TouchableHighlight onPress={()=> alert(item.restaurant.location.city)}>
<Card image={{uri:item.restaurant.thumb}} style={styles.container}>
<Text style={{color:'#000',fontWeight:'bold'}}>{item.restaurant.name} </Text>
</Card>
</TouchableHighlight>
}
/>
)
}
</View>
);
}
};
const styles = StyleSheet.create({
});
I am trying to send the data of the flatlist items when clicked and set to another class.The ontouch is working but I am having the error below in the image. Also how can I send the data of api to the other class and get from another class? I have implemented as follows:
export default class FlatSpeakers extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [],selectedItem: null, }
const { navigate } = this.props.navigation;
}
onPressItem = () => {
navigate('SpeakersClick')
};
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(res => {
this.setState({
isLoading: false,
data: res.data,
})
})
}
renderItem({ item }) {
return (
<TouchableOpacity onPress={()=>this.onPressItem(item)} >
<Card>
<CardSection>
<View style={styles.thumbnailContainerStyle}>
<Image
style={styles.thumbnailStyle}
source={{ uri: item.image }}
/>
</View>
<View style={styles.headerContentStyle}>
<Text style={styles.headerTextStyle}>{item.title}</Text>
<Text>{item.artist}</Text>
</View>
</CardSection>
</Card>
</TouchableOpacity>
)
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
)
}
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem}
keyExtractor={(item, index) => index}
onPress={this.onPressItem}
/>
</View>
);
}
}
Problem in your code is, that you are calling same method from two sides - on one side you are passing arguments in it on another side you are not passing arguments. If you wan't to have both cases covered you should change you onPressFunction, to accept arguments - in your case item:
onPressItem = (item) => {
navigate('SpeakersClick')
};
try to put this.onPressItem = this.onPressItem.bind(this) on constructor(props)
export default class Home extends Component{
constructor(){
super();
const ds = new ListView.DataSource({rowHasChanged:(r1,r2)=>r1!==r2})
this.state={
userDataSource:ds,
}
}
componentDidMount(){
fetch('http://192.168.0.102/giftbaenew/rest/V1/products?searchCriteria[filter_groups][0][filters][0][field]=category_id&searchCriteria[filter_groups][0][filters][0][value]=10',{
headers:{
'Authorization':'Bearer 7dmc9lprh5b1t07hkadyhmtb6etm1jaj'
}
})
.then((response)=>{return response.json()})
.then((responseData)=>{
alert(responseData) // i get the alert message.
this.setState({
userDataSource:this.state.userDataSource.cloneWithRows(responseData)
})
})
}
renderRow(user,sectionId,rowId,highlightRow){
const data=this.state.userDataSource
return(
<View >
<Text style={{color:'black'}}>
{data.items[0].name} //error
</Text>
</View>
)
}
render(){
return(
<ScrollView>
<View>
<View style={styles.container}>
<TouchableOpacity onPress={()=>{this.props.navigation.navigate('Login')}}>
{/* <Text style={{textAlign:'right',marginTop:5,color:'white',fontSize:16}}>Logout</Text> */}
<Image source={require('../Images/logout.png')} style={{width:30,height:30,marginLeft:325}}/>
</TouchableOpacity>
<Text style={styles.text}>
ShakeHands
</Text>
<TextInput placeholder='Search' placeholderTextColor='black' style={{backgroundColor:'white',marginTop:13,height:35,width:320,marginLeft:20,marginRight:20,padding:10}}/>
</View>
<View style={{marginTop:10}}>
<ListView dataSource={this.state.userDataSource} renderRow={this.renderRow.bind(this)}/>
</View>
</View>
</ScrollView>
)
}
}
const styles = StyleSheet.create({
container:{
backgroundColor:'#455a64',
height:125
},
text:{
textAlign:'left',
fontSize:25,
color:'white',
marginTop:0,
marginLeft:18
}
})
I am not able to see anything on my app.
Please help me out.
items[] is an array of JSON data each item has its attributes like name,etc
I m trying to display name but nothing is displayed.
Error is undefined is not an object evaluating data.items[0]
Please try my code it will defenatily resolve your issue
import React, { Component } from 'react';
import { FlatList, ActivityIndicator, Text, View } from 'react-native';
export default class FetchExample extends React.Component {
constructor(props){
super(props);
this.state ={ isLoading: true}
}
componentDidMount(){
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.movies,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render(){
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return(
<View style={{flex: 1, paddingTop:20}}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) => <Text>{item.title}, {item.releaseYear}</Text>}
keyExtractor={(item, index) => index}
/>
</View>
);
}
}
It is not working. I tried everything. Nothing works. state.params is simply not there if you make an advanced app.
I have this problem with the react "navigation". It says in the manual that the params object should be there https://reactnavigation.org/docs/navigation-prop.html#state-the-screen-s-current-state-route But it isn't.
I set an id parameter like this in screen 1 when I link to screen 2:
<TouchableWithoutFeedback onPress={ ()=> this.props.navigation.navigate('FontsTab', { id: item.id }) } style={styles.listHeader} >
<View style={styles.listRowContainer}>
<View style={styles.listinside1Container}>
<Image style={styles.listImage} source={item.icon} />
<View style={styles.listContainer} onPress={(event) => this._selectedItem(item.text)} >
<Text style={styles.listHeader} >
{item.title}
</Text>
<Text style={styles.listValue} >{item.value}</Text>
<Image
style={{width: 50, height: 50}}
source={{uri: item.img}}
/>
</View>
</View>
</View>
</TouchableWithoutFeedback>
But it's not working. In screen 2 I can't use the state.params :
<ScrollView style={styles.container}>
<Text>{ JSON.stringify(this.props.navigation)}</Text>
<Text>TEST{ state.params }</Text>
<Image
style={{width: 150, height: 150}}
source={{uri: this.state.dataSource.img}}
/>
<Text style={styles.textStyle} >{this.state.dataSource.text}</Text>
</ScrollView>
state.params just returns nothing. What can I do about it?
The full class for screen2:
class Fonts extends Component {
constructor(props) {
super(props);
this.state = {
params: null,
selectedIndex: 0,
value: 0.5,
dataSource: null,
isLoading: true
};
this.componentDidMount = this.componentDidMount.bind(this);
}
getNavigationParams() {
return this.props.navigation.state.params || {}
}
componentDidMount(){
return fetch('http://www.koolbusiness.com/newvi/4580715507220480.json')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
...this.state,
isLoading: false,
dataSource: responseJson,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render() {
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return (
<ScrollView style={styles.container}>
<Text>{ JSON.stringify(this.props)}</Text>
<Text>TEST{ this.state.params }</Text>
<Image
style={{width: 150, height: 150}}
source={{uri: this.state.dataSource.img}}
/>
<Text style={styles.textStyle} >{this.state.dataSource.text}</Text>
</ScrollView>
);
}
}
In my app this pain is reproducible by a simple button in screen1:
<Button
onPress={() => navigate('FontsTab', { name: 'Brent' })}
title="Go to Brent's profile"
/>
Then switching to the FontsTab works but the params are not in the state object:
I also have this code for the tabview
import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { StackNavigator } from 'react-navigation';
import { Icon } from 'react-native-elements';
import FontsHome from '../views/fonts_home';
import FontsDetails from '../views/fonts_detail';
const FontsTabView = ({ navigation }) => (
<FontsHome banner="Fonts" navigation={navigation} />
);
const FontsDetailTabView = ({ navigation }) => (
<FontsDetails banner="Fonts Detail" navigation={navigation} />
);
const FontsTab = StackNavigator({
Home: {
screen: FontsTabView,
path: '/',
navigationOptions: ({ navigation }) => ({
title: '',
headerLeft: (
<Icon
name="menu"
size={30}
type="entypo"
style={{ paddingLeft: 10 }}
onPress={() => navigation.navigate('DrawerOpen')}
/>
),
}),
},
Detail: {
screen: FontsDetailTabView,
path: 'fonts_detail',
navigationOptions: {
title: 'Fonts Detail',
},
},
});
export default FontsTab;
this.props.navigation.state.params.id will give you the value of param id passed from screen1.
I put my screen in the right StackNavigator and then it worked.