React Native getting collections from Zomato API - react-native

I am trying to get collections from Zomato API (https://developers.zomato.com/documentation) and I am trying to retrieve the collections list and display them onto a flatList. However every time I try to retrieve it my terminal seems to output undefined
Here is my code
async componentDidMount(){
try {
const res = await axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/collections`,
headers: {
'Content-Type': 'application/json',
'user-key': 'a31bd76da32396a27b6906bf0ca707a2'
},
params: {
'city_id': `${this.state.loca}`
}
});
this.setState({ data: res.data });
console.log(res.data.collections.title)
} catch (err) {
console.log(err);
} finally {
this.setState({ isLoading: false });
}
};
when I console.log(res.data.collections) I get the entire list of all components within the collections Array from the API. However when I try to access the title component; the terminal outputs undefined
what am I doing wrong?

Do check out the below code, i think there was a small problem with your code, you were not extracting the exact data. Ive corrected it by displaying the title of restuarent. you can do more. expo link is as expo-link
import React from 'react';
import {
View,
Text,
FlatList,
StyleSheet,
TouchableHighlight,
Dimensions,
Image,
} from 'react-native';
import Modal from 'react-native-modal';
import { createAppContainer } from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import { Card, Icon, Button } from 'react-native-elements';
import Constants from 'expo-constants';
// import {apiCall} from '../src/api/Zomato';
// import Logo from '../assets/Logo.png';
import axios from 'axios';
export default class HomeScreen extends React.Component {
constructor(props){
super(props);
// this.navigate = this.props.navigation.navigate;
this.state={
data : [],
isModalVisible: false,
loca: 280
}
}
async componentDidMount(){
try {
const res = await axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/collections`,
headers: {
'Content-Type': 'application/json',
'user-key': 'a31bd76da32396a27b6906bf0ca707a2'
},
params: {
'city_id': `${this.state.loca}`
}
});
// alert(res.data.collections, 'response');
this.setState({ data: res.data.collections });
} catch (err) {
console.log(err);
} finally {
}
}
render() {
return (
<View>
<FlatList
style={{marginBottom: 80}}
keyExtractor={item => item.id}
data={this.state.data}
renderItem={({ item }) =>
<TouchableHighlight onPress={()=> this.props.navigation.navigate('CategoryScreen', { category: item.categories.id, city: this.state.loca })}>
<Card>
<Text style={{color:'#000',fontWeight:'bold'}}>{item.collection.title} </Text>
</Card>
</TouchableHighlight>}
/>
</View>
);
}
}
do revert if any doubts, ill clear it. hope it helps;

Axios returns a promise try keeping the setState in .then and stop trusting console.log
axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/collections`,
headers: {
'Content-Type': 'application/json',
'user-key': 'a31bd76da32396a27b6906bf0ca707a2'
},
params: {
'city_id': `${this.state.loca}`
}
}).then( res => this.setState({res}))

Related

How to store API response in state And pass this response value to another screen as params in react native

I am new to react native. I have created A screen. Where I am getting response from API. but now I want to store that response in state. and I want to send that value to another screen by navigation params.
my response is like this ->
Array [
Object {
"phpid": 10,
},
]
here is my code
constructor(props) {
super(props);
this.state={
};
}
fetch('https://xuz.tech/Android_API_CI/uploaddata/t_details?query=', {
method: 'POST',
headers: {'Accept': 'application/json, text/plain, */*', "Content-Type": "application/json" },
body: JSON.stringify([{"==some values=="}])
})
.then((returnValue) => returnValue.json())
.then(function(response) {
console.log(response)
return response.json();
render(){
return (
<View style={{flex: 1}}>
color="black" onPress={() => this.props.navigation.navigate("FormItems",{i want to send value to formitems})} />
</View>
)}
Set your state once you receive your response, then use your state as params when navigating. Once your fetch has been resolved:
this.setState({ response: response.json() });
Sending params to another screen is fairly simple, you just need to pass an object as the second parameter to navigate.
this.props.navigation.navigate('FormItems', {
form: this.state.response,
});
The receiving component will then need to read those params:
class DetailsScreen extends React.Component {
render() {
const { navigation } = this.props;
return (
<Text>{JSON.stringify(navigation.getParam('form', 'some default'))}</Text>
}
}
A full explanation on how to use params with react-navigation v4 can be found here: https://reactnavigation.org/docs/4.x/params
Use it like this. first initialise the state and when you get data from api set the data in state and when button press pass the data to new screen in params.
import React, { Component } from 'react';
import { Text, View } from 'react-native';
export default class Example extends Component {
state = {
data: [], // initialize empty state
};
componentWillMount() {
this.requestData();
}
requestData = () =>{
fetch('https://xuz.tech/Android_API_CI/uploaddata/t_details?query=', {
method: 'POST',
headers: {'Accept': 'application/json, text/plain, */*', "Content-Type": "application/json" },
body: JSON.stringify([{"==some values=="}])
})
.then((returnValue) => returnValue.json())
.then(function(response) {
this.setState({
data:response //set data in state here
})
})
}
render() {
return (
<View style={{ flex: 1 }}>
<Button
color="black"
onPress={() =>
this.props.navigation.navigate('FormItems', {
data: this.state.data, // pass data to second screen
})
}
/>
</View>
);
}
}

losing my mind - why doesn't my fetch re render (redux)

In my project I have many users and many resources (and many user_resources/the join between users and resources).When I POST to user_resources I see it work on my rails backend (as in I see that instance posted) but in my react native front end I don't see it listed upon update. However, once the app is completely refresh (when I stop and restart the expo server), I finally see those items rendered. ANY IDEAS? I've been working on this forever now to no avail and my project is due tmrw, so any help is appreciated.
screen where I post to user_resources:
import React from 'react';
import { ScrollView,SafeAreaView,StyleSheet, Text, View, FlatList, TouchableOpacity,Button, NativeEventEmitter} from 'react-native';
import {connect} from 'react-redux';
import {fetchResources,searchChanged} from '../actions';
import { addUserResource } from '../actions'
import {SearchBar} from 'react-native-elements';
import { MaterialIcons } from '#expo/vector-icons';
import { MaterialCommunityIcons } from '#expo/vector-icons';
class ResourcesScreen extends React.Component {
state = {
search: ''
}
componentDidMount = () =>{
this.props.fetchResources();
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: 0.5,
width: "100%",
backgroundColor: "lightblue",
}}
/>
);
}
handlePress(item) {
debugger
fetch('http://localhost:3000/user_resources', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
body: JSON.stringify({
resource_id: item.id,
user_id: this.props.users.id,
name: item.name,
description:item.description,
link:item.link,
})
})
.then(res => res.json())
.then(data2 => {
console.log(data2)
this.props.addUserResource(data2)
console.log(this.props)
})
}
header = () => {
return <View>
<Text style={styles.header}>Resources</Text>
</View>
}
onSearchChange = text => {
this.setState({search:text})
}
render(){
return(
<SafeAreaView>
<SearchBar placeholderTextColor="white" placeholder="Enter resource name here" onChangeText={this.onSearchChange} value={this.state.search}/>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Add A New Resource',{topicId:this.props.route.params.topicId})} style={styles.buttonitem}>
<Text style={styles.text}>
<MaterialIcons name="add-circle-outline" size={24} color="white"/>Add A New Resource
</Text>
</TouchableOpacity>
<FlatList keyExtractor={(item)=> item.id.toString()} data={this.props.resourceName} ItemSeparatorComponent = { this.FlatListItemSeparator } renderItem={({item}) => {
return <TouchableOpacity style={styles.material2}>
<Text onPress={() => this.props.navigation.navigate('Add A New Resource',{topicId:item.id})} style={styles.listitem}>{item.name}</Text>
<MaterialCommunityIcons name="bookmark-plus" size={50} color="#16a085" backgroundColor='black' onPress={()=>this.handlePress(item)}/>
</TouchableOpacity>
}}
ListHeaderComponent = {this.header}/>
</SafeAreaView>
)
}
}
const mapStateToProps = (state) => {
return {
resourceName: state.resourceReducer.resources,
users: state.userReducer,
search:state.resourceReducer.searchTerm
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchResources: () => dispatch(fetchResources()),
addUserResource,
searchChanged
}
}
export default connect(mapStateToProps,mapDispatchToProps)(ResourcesScreen)
After this I head to the profile page where the user_resources SHOULD be displayed, but aren't
import React from 'react';
import { ScrollView,StyleSheet, Text, View, FlatList, TouchableOpacity} from 'react-native';
import {connect} from 'react-redux';
import {SearchBar} from 'react-native-elements';
import { AntDesign } from '#expo/vector-icons';
class Profile extends React.Component{
handleDelete = (id) => {
debugger
fetch(`http://localhost:3000/user_resources/${id}`, {
method: "DELETE",
headers: {
"Authorization": this.props.users.token
}
})
.then(r => r.json())
.then((delResource) => {
console.log(delResource)
this.props.deleteOneFood(delResource)
console.log('deleted')
this.forceUpdate()
})
}
render(){
return(
<View>
{this.props.users.user_resources.map(singleResource=> {
return <Text key={singleResource.id}>{singleResource.name}</Text>
})}
</View>
)}
}
let deleteOneResource = (id) => {
return {
type: "DELETE_ONE_USER_RESOURCE",
payload: id
}
}
const mapDispatchToProps = {
deleteOneResource
}
const mapStateToProps = (state) => {
return {
users: state.userReducer,
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Profile)
I had a flatlist before but thought that may be causing the issues so rendered it another way, still no luck. I tried forceUpdates as well, still no luck. I'm not sure if the issue is coming from my reducer:
let userInitialState = {
id: 0,
username: "",
name: '',
category: '',
token: "",
user_resources:[],
}
let userReducer = (state = userInitialState, action) => {
switch(action.type){
case "ADD_USERS":
let singleNestedObject = {
...action.users.user,
token: action.users.token
}
return {
...state,
username: action.users.user.username,
token: action.users.token,
id: action.users.user.id,
name: action.users.user.name,
category: action.users.user.category,
user_resources: action.users.user.user_resources
}
case "ADD_ONE_USER_RESOURCE":
let copyOfResources = [...state.user_resources, action.userResources]
return {
...state,
user_resources: copyOfResources
}
default:
return state
}
}
and it's action
export const addUserResource = (resourceInfo) => {
return {
type: "ADD_ONE_USER_RESOURCE",
userResources: resourceInfo
}
}
Please help me find the issue here, I'm losing it.

Infinite FlatList problem - React Native , Expo

I am using Expo for developing react-native applications.
I want to make an Infinite list, but every time onEndReached event is fired, FlatList is refreshed automatically scrolls to the top of the page!
import React, { useState, useEffect } from "react";
import { SafeAreaView, Text, FlatList } from "react-native";
export default function App() {
const [config, setConfig] = useState({
result: [],
page: 0
});
async function fetchData() {
const response = await fetch("http://192.168.2.49:3500/q", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({ page: config.page })
});
const data = await response.json();
setConfig({
result: [...config.result, ...data],
page: config.page++
});
}
const onEndReached = async () => {
await setConfig({
page: config.page++
});
fetchData();
};
useEffect(() => {
fetchData();
}, []);
return (
<SafeAreaView>
<Text>Current Page : {config.page}</Text>
<FlatList
data={config.result}
renderItem={o => <Text>X :{o.item.t.c}</Text>}
keyExtractor={item => item._id}
onEndReached={() => onEndReached()}
onEndReachedThreshold={0}
></FlatList>
</SafeAreaView>
);
}
You are calling setConfig twice, before calling fetchData and after a successful API request. Which triggers a rerender.
I refactored your code, try this.
import React, { useState, useEffect, useCallback } from 'react';
import {
SafeAreaView,
Text,
FlatList,
NativeSyntheticEvent,
NativeScrollEvent,
} from 'react-native';
export default function App() {
const [config, setConfig] = useState({
result: [],
page: 0,
});
const [isScrolled, setIsScrolled] = useState(false);
const fetchData = useCallback(() => {
async function runFetch() {
const response = await fetch('http://192.168.2.49:3500/q', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ page: config.page }),
});
const data = await response.json();
setConfig({
result: [...config.result, ...data],
page: config.page++,
});
}
runFetch();
}, [config.page, config.result]);
const onEndReached = useCallback(() => fetchData(), [fetchData]);
const onScroll = useCallback(
e => setIsScrolled(e.nativeEvent.contentOffset.y > 0),
[],
);
useEffect(() => {
fetchData();
}, [fetchData]);
return (
<SafeAreaView>
<Text>Current Page : {config.page}</Text>
<FlatList
data={config.result}
keyExtractor={item => item._id}
onEndReached={onEndReached}
onEndReachedThreshold={0.1}
onScroll={onScroll}
renderItem={o => <Text>X :{o.item.t.c}</Text>}
/>
</SafeAreaView>
);
}

undefined is an object error in react-native

import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Navigator,
TouchableOpacity,
Image,
TextInput,
TouchableHighlight,
Alert
} from 'react-native';
import Button from 'react-native-button'
import {Actions} from 'react-native-router-flux'
import Home from './Home'
export class Weight extends Component{
constructor(props) {
super(props);
this.state = {
data: '',
data1:'',
textinput:'',
entryDate: '',
systol:''
}
componentDidMount(){
this._onPressButtonGET();
}
_onPressButtonPOST(){
fetch("url", {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"entryDate":"3/2/2017 2:00 AM",
"systol": "120",
"mobileType":"ANDROID",
"userName":"menutest"
})})
.then((response) => response.json())
.then((responseData) => {
Alert.alert(
"Blood pressure data",
"Blood pressure data - " + JSON.stringify(responseData)
)
})
.done();
}
_onPressButtonGET () {
fetch("url", {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({"mobileType":"ANDROID","userName":"menutest"})})
.then((response) => response.json())
.then((responseData) => {
this.setState({ data: JSON.stringify(responseData) })
})
.done();
}
render(){
return(
<View>
<TouchableHighlight onPress={this._onPressButtonPOST}>
<Text>Add</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this._onPressButtonGET.bind(this)}>
<Text>show</Text>
</TouchableHighlight>
<Text>{this.state.responseData.entryDate}</Text>
<Text>{this.state.responseData.systol}</Text>
</View>
);
}
}
module.exports = Weight;
In the above code i am getting like undefined is not an object (evaluating 'this.state.responsedata.entryData'). I have declared EntryDate in constructor, still getting the same error. what is wrong in above code? how to solve that?
use
<Text>{this.state.entryDate}</Text>
I think you should use
<Text>{this.state.entryDate}</Text>
instead of
<Text>{this.state.responsedata.entryDate}</Text>
Check and see whether it will work as you expected. Good luck

Why isn't mailchimp API working with fetch?

I'm trying to add an email address to a mailchimp list I have.
This is for a react native app and I'm trying to implement the request using fetch.
This is my code within the component:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { connect } from 'react-redux';
import { emailChanged, nameChanged, addToWaitingList } from '../actions';
import { Card, CardSection, Input, Button, Spinner } from '../components/Auth';
class addToWaitingListForm extends Component {
onEmailChange(text) {
this.props.emailChanged(text);
}
onButtonPress() {
const { email } = this.props;
this.props.addToWaitingList({ email });
}
renderButton() {
if (this.props.loading) {
return <Spinner size="large" />;
}
return (
<Button onPress={this.onButtonPress.bind(this)}>
Keep me in the loop!
</Button>
);
}
render() {
return (
<View>
<Card>
<CardSection>
<Input
placeholder="your name"
onChangeText={this.onNameChange.bind(this)}
value={this.props.name}
/>
</CardSection>
<CardSection>
<Input
placeholder="email#uni.ac.uk"
onChangeText={this.onEmailChange.bind(this)}
value={this.props.email}
/>
</CardSection>
<Text style={styles.errorTextStyle}>
{this.props.error}
</Text>
<CardSection style={{ borderBottomWidth: 0 }}>
{this.renderButton()}
</CardSection>
</Card>
</View>
);
}
}
const mapStateToProps = ({ auth }) => {
const { email, name, error, loading } = auth;
return { email, name, error, loading };
};
export default connect(mapStateToProps, {
emailChanged,
addToWaitingList
})(addToWaitingListForm);
Add this is my action code for interacting with the mailchimp api:
import Router from '../../navigation/Router';
import { getNavigationContext } from '../../navigation/NavigationContext';
export const addToWaitingList = ({ email }) => {
const emailListID = 'e100c8fe03';
fetch(`https://us13.api.mailchimp.com/3.0/lists/${emailListID}/members/`, {
method: 'POST',
body: JSON.stringify({
'email_address': email,
'status': 'subscribed',
'merge_fields': {
'FNAME': 'Urist',
'LNAME': 'McVankab'
}
})
})
.then(() => addSubscriberSuccess())
.catch(error => console.log(error));
};
const addSubscriberSuccess = () => {
getNavigationContext().getNavigator('root').immediatelyResetStack([Router.getRoute('auth')]);
};
Right now, the error I'm just getting back is ExceptionsManager.js:62 Cannot read property 'type' of undefined and Error: unsupported BodyInit type
What does this mean and how can I fix this?
You need to do two things.
First off you need to send the basic authentication via fetch so you cant do "user:pass" You have to convert it with btoa('user:pass').
Then you have to send it with mode: 'no-cors'
let authenticationString = btoa('randomstring:ap-keyxxxxxxx-us9');
authenticationString = "Basic " + authenticationString;
fetch('https://us9.api.mailchimp.com/3.0/lists/111111/members', {
mode: 'no-cors',
method: 'POST',
headers: {
'authorization': authenticationString,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
email_address: "dude#gmail.com",
status: "subscribed",
})
}).then(function(e){
console.log("fetch finished")
}).catch(function(e){
console.log("fetch error");
})