i am trying to fetch a Post request but im not getting any value and my app stuck on (loading menu...) i don't know what to do - json

this is my code
so in the fetch() function i am getting the response but i am nit getting any object or values and my app stuck at (loading view...) function
var REQUEST_URL = 'http://awaissaleem.com/json/api.php';
class test extends Component {
constructor(props) {
super(props);
this.state = {
menu: null,
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
fetch(REQUEST_URL, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
menu : 'menu',
active : '1',
})
}).then((response) => response.text())
.then((responseData) => {
this.setState({
menu: responseData.Response,
});
})
.catch((error) => {
console.warn('error',error);
})
.done();
}
render() {
if (!this.state.menu) {
return this.renderLoadingView();
}
var menus = this.state.menu[0];
console.log('menus',menus);
return this.renderMovie(menus);
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>
Loading menu...
</Text>
</View>
);
}
renderMovie(menus) {
return (
<View style={styles.container}>
<View style={styles.rightContainer}>
<Text style={styles.title}>{menus.menu_type}</Text>
<Text style={styles.year}>{menus.menu_no}</Text>
</View>
</View>
);
}
}
so please point me out where i am missing something..

Related

I have this issue undefined is not an object (evaluating 'this.state.dataSource.map')

I want to display a list of places from a online json url.
import React, { Component } from "react";
import {
View,
StyleSheet,
Dimensions,
Image,
StatusBar,
TextInput,
TouchableOpacity,
Text,
Button,
Platform,
Alert,
FlatList,
ActivityIndicator,
} from "react-native";
let url = "https://cz2006api.herokuapp.com/api/getAll";
let url2 = "";
export default class ClinicComponent extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: null,
};
}
componentDidMount() {
return fetch("https://cz2006api.herokuapp.com/api/getAll")
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.data.data,
});
})
.catch((error) => {
console.log(error);
});
}
render() {
if (this.state.isLoading) {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
);
} else {
let hospitals = this.state.dataSource.map((val, key) => {
return (
<View key={key} style={styles.item}>
<Text>{val.name}</Text>
</View>
);
});
return (
<View style={styles.item}>
{/* <Text>Content Loaded</Text> */}
{hospitals}
</View>
);
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
item: {
flex: 1,
alignSelf: "stretch",
margin: 10,
alignItems: "center",
justifyContent: "center",
borderBottomWidth: 1,
borderBottomColor: "#eee",
},
});
Unfortunately when i tried to run this via expo cli I got an error, saying undefined is not an object
enter image description here
Can anyone help me pls!!! I would just like to have a list of hospitals which are scrollable. Thank you!
The URL of the Json is here: https://cz2006api.herokuapp.com/api/getAll
Simply change your initial state to something like this
this.state = {
isLoading: true,
dataSource: [], // <-- here
};
Your problem is you're using dataSource.map but during api calling your dataSource still stay null until it get its response, and null object have no attribute map. That's the cause of your problem.
remove the return in componentDidMount:
componentDidMount() {
fetch("https://cz2006api.herokuapp.com/api/getAll")
.then((response) => response.json())
.then((responseJson) => {
this.setState({
dataSource: responseJson.data.data,
isLoading: false,
});
})
.catch((error) => {
console.log(error);
});
}
I agree with #Nguyễn's suggestion that your initial state should be an array. However the root of the issue seems to be getting the right properties off off your JSON response.
First, you want responseJson.data instead of responseJson.data.data. That gives me an array and shows a long list but the titles are all blank. That's because your response has Name as an uppercase property but you are accessing name. So you need to change that as well.
export default class ClinicComponent extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: [],
};
}
componentDidMount() {
return fetch('https://cz2006api.herokuapp.com/api/getAll')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.data,
});
})
.catch((error) => {
console.log(error);
});
}
render() {
//console.log(this.state.dataSource?.[0]);
if (this.state.isLoading) {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
);
} else {
return (
<View style={styles.item}>
{/* <Text>Content Loaded</Text> */}
{this.state.dataSource.map((val, key) => (
<View key={val._id} style={styles.item}>
<Text>{val.Name}</Text>
</View>
))}
</View>
);
}
}
}
You are fetching a huge amount of data and you probably want some sort of pagination with infinite scrolling. It is extremely slow to load due to the huge payload that we are fetching.
You also have double-escape problem in the JSON response inside the geocodingData section. You want to return this data as an object but it is an escaped string with lots of \" instead.

React Native fetch API response not displaying

I am creating an app using expo. You can check the snack here
I am also giving the code here:
import React, {Component} from 'react';
import { ActivityIndicator, Text, View, StyleSheet, FlatList, Alert, TouchableOpacity } from 'react-native';
import {Avatar, Card, Button, Divider, ListItem, Image} from 'react-native-elements';
import Icon from 'react-native-vector-icons/FontAwesome';
import Constants from 'expo-constants';
import HTML from 'react-native-render-html';
import UserAvatar from 'react-native-user-avatar';
import { StackNavigator } from 'react-navigation';
import { createAppContainer} from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
class HomeScreen extends React.Component{
static navigationOptions =
{
title: '',
};
constructor(props){
super(props);
this.state = {
Loading : true,
data : []
}
}
fetchLeash(){
fetch('https://lishup.com/app/')
.then((response) => response.json())
.then((responseJson) => {
this.setState({ data: responseJson, Loading:false });
}).catch((error) => {
Alert.alert('error!');
});
}
fetchImage(getimg){
fetch('https://lishup.com/app/fetch-image.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
image: getimg
})
}).then((response) => response.json())
.then((responseJson) => {
return (<Text>responseJson.url</Text>);
}).catch((error) => {
Alert.alert('error');
});
}
componentDidMount(){
this.fetchLeash();
}
renderLeash = ({ item }) => (
<View>
<Card style={{ height:100, justifyContent: 'center', alignItems: 'center' }}>
<ListItem
leftAvatar={{
title: item.user,
source: { uri: item.userpic },
}}
title={item.user}
subtitle={item.time}
chevron
/>
<Divider style={{margin:5, backgroundColor:'white'}} />
<HTML html={item.text} />
{this.fetchImage(item.images)}
</Card>
</View>
)
render(){
if(this.state.Loading == true){
return(
<ActivityIndicator size="large" style={{marginTop:100}} color="#0000ff" />
);
}else{
return(
<View>
<FlatList style={{width:400}}
data={this.state.data}
renderItem={this.renderLeash} />
</View>
);
}
}
}
const styles = StyleSheet.create({
});
const RootStack = createStackNavigator(
{
Home: { screen: HomeScreen },
},
{
initialRouteName: 'Home',
}
);
export default createAppContainer(RootStack);
If you run the snack in your device, you will see that the posts(fetchLeash() function) is working fine. But the fetchImage() is returning nothing.
My fetch-image.php file is here:
<?php
// Importing DBConfig.php file.
include 'DB.php';
header('Content-Type: application/json');
// Creating connection.
$con = mysqli_connect($HostName,$HostUser,$HostPass,$DatabaseName);
// Getting the received JSON into $json variable.
$json = file_get_contents('php://input');
// decoding the received JSON and store into $obj variable.
$obj = json_decode($json,true);
// Populate User email from JSON $obj array and store into $email.
$image = $obj['image'];
if($image == "") {
$blank[] = array("url"=>"");
echo json_encode($blank);
}else{
//query to get image url with the code received
$Sql_Query = "SELECT * FROM `leash_img` WHERE `pid`= '".$image."' ";
// Executing SQL Query.
$check = mysqli_query($con,$Sql_Query);
if($check){
while($row=mysqli_fetch_assoc($check)){
$SuccessLoginMsg[] = array("url"=> $row['image']);
}
// Converting the message into JSON format.
$SuccessLoginJson = json_encode($SuccessLoginMsg);
echo $SuccessLoginJson;
}
}
?>
This returns like the following:
[{"url":"link here"}]
The PHP file is working fine. But the react native fetchImage() is not working.
I am totally new to react native. So forgive my problems. I am just out of my ideas. Please help me.
You can't asynchronously render UI from the render function, you need to fetch the data outside it in one of the lifecycle functions and conditionally render UI while it is being fetched.
Once the data has been fetched you should go ahead and fetch the image urls. Use Promise.all and map each response item to a fetch request. This will allow all image url fetches to resolve asynchronously and maintain index order.
fetchLeash() {
fetch('https://lishup.com/app/')
.then((response) => response.json())
.then((responseJson) => {
this.setState({ data: responseJson });
Promise.all(responseJson.map(({ images }) => this.fetchImage(images)))
.then((images) => {
this.setState({ imageUrls: images.map(url => ({ uri: url })) })
});
})
.catch((error) => {
Alert.alert('error!');
})
.finally(() => {
this.setState({ Loading: false });
});
}
The other important change is that the image response is an array of length 1, so need to access correctly.
fetchImage(image) {
return fetch('https://lishup.com/app/fetch-image.php', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ image }),
})
.then((response) => response.json())
.then((responseJson) => responseJson[0].url);
}
Now you can conditionally render an Image if the url at that index exists.
renderLeash = ({ item, index }) => (
<View>
<Card
style={{ height: 100, justifyContent: 'center', alignItems: 'center' }}>
<ListItem
leftAvatar={{
title: item.user,
source: { uri: item.userpic },
}}
title={item.user}
subtitle={item.time}
chevron
/>
<Divider style={{ margin: 5, backgroundColor: 'white' }} />
<HTML html={item.text} />
<Text>
{this.state.imageUrls[index] && this.state.imageUrls[index].uri}
</Text>
{this.state.imageUrls[index] && (
<Image
source={this.state.imageUrls[index]}
style={{ width: 100, height: 100 }}
PlaceholderContent={<ActivityIndicator />}
/>
)}
</Card>
</View>
);
Expo Snack
EDIT Allow display of all fetched image URLs. Instead of grabbing and returning just the first URL, return an array of URLs. Below I mapped the URLs to a new array before returning them, and these can be set directly in state now. Update the render function to use an additional guard (array length check) and render null if array doesn't exist. (Could also use another FlatList here if you wanted to)
fetchLeash() {
return fetch('https://lishup.com/app/')
.then((response) => response.json())
.then((responseJson) => {
this.setState({ data: responseJson });
Promise.all(
responseJson.map(({ images }) => this.fetchImage(images))
).then((imageUrls) => this.setState({ imageUrls }));
})
.catch((error) => {
Alert.alert('error!');
})
.finally(() => {
this.setState({ Loading: false });
});
}
fetchImage(image) {
return fetch('https://lishup.com/app/fetch-image.php', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ image }),
})
.then((response) => response.json())
.then((responseJson) =>
// Filter elements with empty string URLs, then app just the URL
responseJson.filter(({ url }) => url).map(({ url }) => url)
);
}
...
{this.state.imageUrls[index] && this.state.imageUrls[index].length
? this.state.imageUrls[index].map((uri) => (
<Image
source={{ uri }}
style={{ width: 100, height: 100 }}
PlaceholderContent={<ActivityIndicator />}
/>
))
: null}

react native how to iterate over json data and render in component

im new to react native and i have been able to fetch json data from server successfully. how do i pass the object into an array and render in my component. Here is my code
i've tried iterating over the object using .map() and i get "undefined is not a function". Ive also tried to convert the object into an array using Object.values and i get error "value for message cannot be cast from readablenativearray to string"
constructor(props) {
super(props);
//useraccountdetails will contain the object from the server
this.state = {
useraccountdetails: [],
}
this.loaduser_account_details= this.loaduser_account_details.bind(this)
}
componentWillMount() {
//this function will fetch the data from the server
this.loaduser_account_details()
}
loaduser_account_details() {
fetch('http://10.162.101.247/camfilaapiv2/commands/loggedin_user_account_details.php', {
method: 'POST',
headers: {
'Accept': 'text/plain',
'Content-Type': 'text/plain',
},
body: JSON.stringify({
globaluseridDB: modulevariables.globaluserid,
})
}).then((response) => response.text())
.then((responseJson) => {
var jsonconvertedrows = JSON.parse(responseJson);
var finaldata = JSON.stringify(jsonconvertedrows)
this.setState({ useraccountdetails: finaldata });
Alert.alert("User details", this.state.useraccountdetails)
}).catch((error) => {
console.error(error);
})
}
//alert(this.state.useraccountdetails) gives me this [{"user_id":"107","username":"sam","year":"6"}]
render(){
return (
/**page setup */
<View style={{ backgroundColor: '#203546', flex: 1, flexDirection: 'column' }}>
{/**body */}
<Grid>
{
this.state.useraccountdetails.map((count)=>{
<Text>{count.username}</Text>
})
}
</Grid>
</View>
)
}
It looks like it is because you are iterating over a string in your render. this.state.useraccountdetails is a string once your response is successful as you are setting it as the result stringified. To correct this all you will need to do is correct your setState to
this.setState({ useraccountdetails: jsonconvertedrows });
Can you try the following code?
constructor(props) {
super(props);
//useraccountdetails will contain the object from the server
this.state = {
useraccountdetails: [],
}
this.loaduser_account_details= this.loaduser_account_details.bind(this)
}
componentWillMount() {
//this function will fetch the data from the server
this.loaduser_account_details()
}
loaduser_account_details() {
fetch('http://10.162.101.247/camfilaapiv2/commands/loggedin_user_account_details.php', {
method: 'POST',
headers: {
'Accept': 'text/plain',
'Content-Type': 'text/plain',
},
body: JSON.stringify({
globaluseridDB: modulevariables.globaluserid,
})
}).then((response) => response.json())
.then((responseJson) => {
//var jsonconvertedrows = JSON.parse(responseJson);
//var finaldata = JSON.stringify(jsonconvertedrows)
this.setState({ useraccountdetails: responseJson });
Alert.alert("User details", this.state.useraccountdetails)
}).catch((error) => {
console.error(error);
})
}
//alert(this.state.useraccountdetails) gives me this [{"user_id":"107","username":"sam","year":"6"}]
render(){
return (
/**page setup */
<View style={{ backgroundColor: '#203546', flex: 1, flexDirection: 'column' }}>
{/**body */}
<Grid>
{
return this.state.useraccountdetails.map((count)=>{
return(
<Text>{count.username}</Text>
)
})
}
</Grid>
</View>
)
}
You are try to change the response to 'text', please change it from response.text() to response.json()
Change this.setState({ useraccountdetails: Object.values(jsonconvertedrows) }); as shown in code and try it:
loaduser_account_details() {
fetch('http://10.162.101.247/camfilaapiv2/commands/loggedin_user_account_details.php', {
method: 'POST',
headers: {
'Accept': 'text/plain',
'Content-Type': 'text/plain',
},
body: JSON.stringify({
globaluseridDB: modulevariables.globaluserid,
})
}).then((response) => response.text())
.then((responseJson) => {
var jsonconvertedrows = JSON.parse(responseJson);
var finaldata = JSON.stringify(jsonconvertedrows)
this.setState({ useraccountdetails: Object.values(finaldata) });
Alert.alert("User details", this.state.useraccountdetails)
}).catch((error) => {
console.error(error);
})
}

How to fetch data from URL and then store it in AsyncStorage in React Native?

I'm trying to fetch data from URL and then store it in AsyncStorage in React Native.
This is screen where "magic" happens:
class CardsScreen extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: null,
}
}
componentDidMount() {
return fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
isLoading: false,
dataSource: responseData,
});
})
.catch((error) => {
console.log(error)
});
}
render() {
if (netStatus) {
if (this.state.isLoading) {
return (
<View style={styles.container}>
<ActivityIndicator/>
</View>
)
} else {
let data = this.state.dataSource.map((val, key) => {
return <View key={key} style={styles.itemWrapper}>
<View style={styles.titleWrapper}>
<Text style={styles.content}>{val.type}</Text>
<Text style={styles.title}>{val.title}</Text>
<Text style={styles.content}>{val.date}</Text>
</View>
<View style={styles.imageWrapper}>
<Image
style={styles.image}
source={{uri: val.image}}
/>
</View>
<View style={styles.contentWrapper}>
<Text style={styles.content}>{val.adress}</Text>
<Text style={styles.content}>{val.text}</Text>
</View>
</View>
})
return (
<ScrollView contentContainerStyle={styles.containerScroll}>
{data}
</ScrollView>
);
}
} else {
return <View style={styles.contentWrapper}>
<Text style={styles.content}>Not connected!</Text>
</View>
}
}
};
This code prints data if device is connected to internet.
What I need to do is if device is conneted to internet, fetch data from URL and store (or overwrite) it in AsyncStorage, and then print data on screen. If device is not connect to the internet just print data from AsyncStorage.
This is example of .json I call from URL:
[
{
"type": "Party",
"title": "New party comming to town!",
"adress": "New Yrok",
"date": "20. 4. 2019.",
"image": "https:\/\/some-url.com\/some-image.jpg",
"text": [
"Some description"
],
"_id": "events_1"
}
]
I can't find any similar solution, so I would be greatfull if someone has tutorial that could help me with this.
EDIT (little more of explenation):
This is what I want to do:
If device is connected to the internet, update AsyncStorage with data from URL and then display that new data in AsyncStorage. If device is not connected to the internet, just display data that is AsyncStorage. And there are multiple "events", not just one like in the example.
export default class BankDetails extends Component {
constructor(props) {
super(props)
this.state = {
userToken: null,
userData: {
nameOfBank: '',
account_umber: '',
account_holder_ame: ''
}
}
}
async componentDidMount () {
try {
let value = await AsyncStorage.getItem('userData')
let userDetails = JSON.parse(value)
if (userDetails !== null) {
let userData= Object.assign({}, this.state.userData)
userData.nameOfBank = userDetails.nameOfBank
userData.account_umber = userDetails.account_umber
userData.account_holder_ame = userDetails.account_holder_ame
this.setState({
userToken: userDetails.token,
userData
})
}
} catch (error) {
console.log(error)
}
}
onBankChange = (nameOfBank) => {
this.setState({userData: {...this.state.userData, nameOfBank:nameOfBank}})
}
saveBankDetailsEdit = () => {
const { nameOfBank,account_umber, account_holder_ame }= this.state.userData
let {userToken} = this.state
var formData = new FormData()
formData.append('bank', nameOfBank)
formData.append('account_number', account_umber)
formData.append('account_title', account_holder_ame)
fetch('http://xxxx/update', {
method: 'POST',
headers: {
'X-API-KEY': '123456',
'Authorization': userToken
},
body: formData
}).then(function (response) {
console.log(response)
AsyncStorage.getItem('userData').then(
data => {
data = JSON.parse(data)
data.nameOfBank = nameOfBank
data.account_umber = account_umber
data.account_holder_ame = account_holder_ame
AsyncStorage.setItem('userData', JSON.stringify(data))
}
)
let data = JSON.parse(response._bodyText)
Alert.alert(data.message)
})
.catch((error) => {
console.log(error)
})
.done()
}
This is how I have done my job. Hope this helps.
You need to store your response like this
note one thing when you set value into AsyncStorage you need to store as string JSON.stringify() value into storage.
onSave = async () => {
try {
await AsyncStorage.setItem("key", JSON.stringify(responseData));
Alert.alert('Saved', 'Successful');
} catch (error) {
Alert.alert('Error', 'There was an error.')
}
}
and when you get value from AsyncStorage you need to JSON.parse()
onSave = async () => {
try {
const storedValue = await AsyncStorage.getItem("key");
this.setState({ storedValue: JSON.parse(storedValue) });
} catch (error) {
Alert.alert('Error', 'There was an error.')
}
}
hope it will help you

fetching of json from url is stuck

Trying to fetch some json from the following url: https://talaikis.com/api/quotes/random/
I'm using an activity indicator while waiting for the json to be fetched. That apparently never happens and so the app just displays the activity indicator. I tried using the sample that is provided in the networking tutorial in the official react native documentation
Here is the code:
import React, { Component } from 'react';
import {AppRegistry, StyleSheet, Text, View, ActivityIndicator} from 'react-native';
import Header from '../header/Header';
export default class SingleQuote extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true
}
}
loadingQuoteFromUrl(){
return fetch('https://talaikis.com/api/quotes/random/')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render() {
var style = require("./styles.js");
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return (
<View style={style.container}>
<Header text="Daily Quote" />
<View style={style.textContainer}>
<Text
adjustsFontSizeToFit
numberOfLines={3}
style={style.textStyle}
>
{this.state.dataSource.quote}
</Text>
<Text
adjustsFontSizeToFit
numberOfLines={1}
style={style.textStyle}
>
{this.state.dataSource.author}
</Text>
</View>
</View>
);
}
}
You are not invoking loadingQuoteFromUrl anywhere in your App. For fetch operations componentDidMount is a suitable lifecycle method. So, you can use it. But first, you should bind this function in order to use this context. You can do this in the constructor or define it as an arrow function without binding.
class SingleQuote extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true
};
this.loadingQuoteFromUrl = this.loadingQuoteFromUrl.bind(this);
}
componentDidMount() {
this.loadingQuoteFromUrl();
}
loadingQuoteFromUrl() {
return fetch("https://talaikis.com/api/quotes/random/")
.then(response => response.json())
.then(responseJson => {
this.setState(
{
isLoading: false,
dataSource: responseJson
},
function() {}
);
})
.catch(error => {
console.error(error);
});
}
render() {
if (this.state.isLoading) {
return <div>Loading...</div>;
}
return (
<div>
<div>
<p>{this.state.dataSource.quote}</p>
<p>{this.state.dataSource.author}</p>
</div>
</div>
);
}
}
ReactDOM.render(<SingleQuote />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
class SingleQuote extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true
};
}
componentDidMount() {
this.loadingQuoteFromUrl();
}
loadingQuoteFromUrl = () => {
return fetch("https://talaikis.com/api/quotes/random/")
.then(response => response.json())
.then(responseJson => {
this.setState(
{
isLoading: false,
dataSource: responseJson
},
function() {}
);
})
.catch(error => {
this.setState(
{
isLoading: false,
}
console.error(error);
});
}
render() {
const { isLoading } = this.state;
const { dataSource } = this.props;
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
<div>
<p>{dataSource.quote}</p>
<p>{dataSource.author}</p>
</div>
</div>
);
}
}
ReactDOM.render(<SingleQuote />, document.getElementById("root"));