Inability to get data from API react native - javascript

Hi so my main question is when making a api call to https://newsdata.io, i want to access the results method on the object the api returns. However react native is saying results is undefined. Why cant i see the data object but not the methods attached to the data variable.
import React from 'react'
import { Text, View, Image } from 'react-native'
export const Feed = () => {
async function data() {
const response = await fetch('https://newsdata.io/api/1/news?apikey=pub_11306c8c5e2932eab7155edacbc6339247174&q=web%203')
const data = await response.json()
const results = data.results;
const imageURLDATA = results.forEach(element => {
console.log(element.image_url)
})
}
data()
return (
<View>
<Text style={{fontSize: 40, fontWeight: "700", marginTop: 20}}>Feed</Text>
{results.forEach(element => {
<View>
< Image source={{
uri: `${element.image_url}`
}}/>
</View>
})}
</View>
)
}

You need to take the component lifecycle into consideration. Use useState to create a variable that trigger component rerenders and useEffect to call functions at certain events:
import React, { useState, useEffect } from 'react';
import { View, Image, Text } from 'react-native';
export const Feed = () => {
const [feedData, setFeedData] = useState([]);
async function getData() {
// you may want to change your api key
const response = await fetch(
'https://newsdata.io/api/1/news?apikey=pub_11306c8c5e2932eab7155edacbc6339247174&q=web%203'
);
const data = await response.json();
const results = data.results;
setFeedData(results);
}
//will call provided function when items in array is updated
useEffect(() => {
console.log('Feed data updated')
feedData.forEach((element) => {
console.log(element.image_url);
});
}, [feedData]);
// will call provided function once after first render
useEffect(() => {
getData();
}, []);
return (
<View>
<Text style={{ fontSize: 40, fontWeight: '700', marginTop: 20 }}>
Feed
</Text>
{/*forEach returns null, map returns value*/}
{feedData.map((element) => (
<View>
<Image
source={{
uri: `${element.image_url}`,
}}
// provide width to element or it wont render
style={{width:100,height:100}}
/>
</View>
)
)}
</View>
);
};
export default Feed;
Here's a demo

Related

firebase realtime database is not getting fetched with onPress in react native, have to refresh the ref().on function everytime

I have a realtime database with main node 'user' and then inside it i have 3 child nodes and those 3 child nodes have 4 more child nodes, each of them. One of the 4 nodes is a recording, one is image and 2 of them are strings. I am trying to fetch them dynamically with Next and Back button where on pressing next, next node's data is displayed on screen.
I am using a useState for dynamically changing the path of database (ref), but on pressing the next/back button, my data on screen does not get updated. Also later I found out that after pressing next/back button when I refresh/rewrite the ref().on function, my data gets updated, but I have to do this for every press.
Here's my App.js code:
import Sound from 'react-native-sound';
import database from '#react-native-firebase/database';
import storage from '#react-native-firebase/storage';
import React , {useEffect, useState} from 'react';
import {
ScrollView,
StyleSheet,
Alert,
Text,
View,
Image,
Button
} from 'react-native';
const App = () => {
const [myData,setData] = useState({
letter:'',
pronun:'',
word:'',
image:''
});
const [img,setimg] = useState(null);
const [pronunn,setpronun] = useState(null);
const [hey,sethey] = useState(1);
useEffect(() => {
getDatabase();
}, []);
function getDatabase() {
database().ref('users/'+hey+'/').on('value' , (snapshot) => {
Sound.setCategory('Playback', true);
var poo=new Sound(snapshot.val().pronun);
setData({
letter: snapshot.val().letter,
word: snapshot.val().word,
image: setimg(snapshot.val().image),
pronun: setpronun(poo)
});
console.log(snapshot.val());
});
}
return (
<View style={{flex:1, backgroundColor:'#000000', alignContent:'center', alignItems:'center', justifyContent:'center'}}>
<ScrollView>
<Text style={{color:'#ffff'}}>
Letter: {myData ? myData.letter : 'loading...' }
</Text>
<Text style={{color:'#ffff'}}>
Word: {myData ? myData.word : 'loading...' }
</Text>
<Image style={{width:200, height:200}}
source={{uri: img}}
/>
<View>
<Button
title='Pronunciation'
onPress={() => {
return pronunn.play();
}}
>
</Button>
<Button title='Next' onPress={
() => {
if (hey>2) {
Alert.alert('no more records');
}
else {
return sethey(hey+1);
}
}
}
>
</Button>
<Button title='back' onPress={
() => {
if (hey<2) {
Alert.alert('no more records to go back');
}
else {
return sethey(hey-1);
}
}
}
>
</Button>
</View>
</ScrollView>
</View>
);
};
export default App;
Since your setData hook/effect depends on the hey state, you need to specify the latter as a dependency in useEffect for the data loading.
useEffect(() => {
getDatabase();
}, [hey]);
Also see:
The documentation on useEffect, specifically the section on dependencies.
setState in React's useEffect dependency array

ReactNative - get data from promise (JSON)

I am able to fetched the JSON data and it now returns an array. How do I use the elements in the array in react native? Below is my attempt:
export default function display() {
const fetching = async() => ... //defines fetching() which returns the array
...
return (
<View>
<Image
source = {{uri: 'http://imageURI.' + fetching().then((arr) => {return arr[0]}) + '.png'}}
style = {{height: 50, width: 50, borderRadius: 50}} />
</View>
)
}
How can I access the elements in the array?
Try the following.
You need to make your API call asynchronously, display something until you get the response and then update the state with retrieved data.
import React, {useState, useEffect} from 'react';
import {View, Image} from 'react-native'
const fetch = async () => {/* ASYNC LOGIC HERE*/};
const MyComponent = () => {
const [uri, setUri] = useState(null);
useEffect(() => {
fetch().then((arr) => {
setUri(`http://imageURI.${arr[0]}.png`);
});
}, []);
return (
<View>
{
uri ? <Image source={{uri}} style={{height: 50, width: 50, borderRadius: 50}} /> : null
}
</View>
);
};
I agree with ernesto, I would just do all my logic in the fetching function and for me if you get an array it is for several elements so I would prepare that with a map method
import React, { useState, useEffect } from "react";
import { View, Image } from "react-native";
const Display = () => {
const [state, setState] = useState(null);
const fetching = async () => {
try {
const response = await fetch("api.exemple");
const imagesArray = await response.json();
setState(imagesArray);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
fetching();
}, []);
return (
<View>
{state &&
state.map((fileName) => {
const uri = `http://imageURI.${fileName}.png`;
return (
<Image
source={{ uri }}
style={{ height: 50, width: 50, borderRadius: 50 }}
/>
);
})}
</View>
);
};
export default Display;

TypeError: undefined is not an object (evaluating ' _this.setState')

i'm a complete beginner to React Native and i'm trying to add items to flatlist using textinput. i keep constantly getting a TypeError: undefined is not an object (evaluating'_this.setState'). i have edited the code many times and tried to research what i can do, but it still is not working properly. could someone help me and tell me what i need to change? below is my code.
thank you in advance!
import React, { useState, setState } from 'react';
import { View, Text, StyleSheet, FlatList, Alert, TouchableOpacity, TextInput } from 'react-native';
export default function FlatlistComponent({ }) {
const array = [{title: 'ONE'}, {title: 'TWO'}];
const [arrayHolder] = React.useState([]);
const [textInputHolder] = React.useState('');
const componentDidMount = () => {
setState({ arrayHolder: [...array] })
}
const joinData = () => {
array.push({ title : textInputHolder });
this.setState({ arrayHolder: [...array] });
}
const FlatListItemSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#607D8B",
}} />
);
}
const GetItem = (item) => {
Alert.alert(item);
}
return (
<View style={styles.MainContainer}>
<TextInput
placeholder="Enter Value Here"
onChangeText={data => this.setState({ textInputHolder: data })}
style={styles.textInputStyle}
underlineColorAndroid='transparent'
/>
<TouchableOpacity onPress={joinData} activeOpacity={0.7} style={styles.button} >
<Text style={styles.buttonText}> Add Values To FlatList </Text>
</TouchableOpacity>
<FlatList
data={arrayHolder}
width='100%'
extraData={arrayHolder}
keyExtractor={(index) => index.toString()}
ItemSeparatorComponent={FlatListItemSeparator}
renderItem={({ item }) => <Text style={styles.item} onPress={GetItem.bind(this, item.title)} > {item.title} </Text>}
/>
</View>
);
}
So I see you're trying to use functional components here.
State variables can be rewritten like this
const [arrayHolder, setArrayHolder] = useState([]);
const [textInputHolder, setTextInputHolder] = useState('');
componentDidMount is used in class components and can be rewritten like this for functional components
import React, { useState, useEffect } from 'react';
useEffect(()=>{
setArrayHolder(array)
}, [])
Function joinData can be re-written like this.
const joinData = () => {
array.push({ title : textInputHolder });
setArrayHolder(array)
}
About the text not showing up. You're using this.setState in the onChangeText event. It is a functional component and this won't work in a functional component.state variables are declared and set using the useState hook in a functional component.
You should rewrite the onChangeText event like this.
<TextInput
placeholder="Enter Value Here"
onChangeText={data => setTextInputHolder(data)}
style={styles.textInputStyle}
underlineColorAndroid='transparent'
/>
I think this'll solve your problem

How to store the data when fetching from API

I create an application that retrieves data from a URL and display it. I'm a beginner and therefore I do not use Redux or other for the moment.
I managed to recover the data and display it on my application but I would like to use the local storage of the phone. I saw the examples for AsyncStorage on the documentation of the Expo website but I don't know how to adapt them to my code. In addition, do I have to display local storage data only when there is no internet connection? Or do I always still have to display them?
import React, {Component} from 'react';
import {ScrollView, View, FlatList, Image, ActivityIndicator} from 'react-native';
import {ListItem} from "react-native-elements";
import {createAppContainer, createStackNavigator} from "react-navigation";
import PronosticsDetailsScreen from "../../screens/PronosticsDetailsScreen";
import AppConfig from "../../AppConfig";
class MontanteTab extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
};
}
componentDidMount() {
return fetch('https://myurl.com')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson
}, function () {
});
})
.catch((error) => {
console.error(error);
});
}
render() {
if (this.state.isLoading === true) {
return (
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return (
<View>
<ScrollView>
<View>
<FlatList
data={this.state.dataSource}
keyExtractor={(item, index) => index.toString()}
renderItem={({item}) => (
<ListItem
key={item.id}
roundAvatar
badge={{
value: item.statut,
textStyle: {color: '#fff'},
containerStyle: {marginRight: 0, backgroundColor: item.couleur}
}}
avatar={<Image
source={{uri: 'https://myurl.com/' + item.image}}
style={{borderRadius: 50, height: 50, width: 50}}/>}
title={item.competition}
subtitle={item.equipe_domicile + ' - ' + item.equipe_exterieur}
onPress={() => this.props.navigation.navigate('PronosticsDetails', {
item,
})}
/>
)}
/>
</View>
</ScrollView>
</View>
);
}
}
EDIT :
I tried this, but my data are not displayed :
import React, {Component} from 'react';
import {ScrollView, View, FlatList, Image, ActivityIndicator, AsyncStorage} from 'react-native';
import axios from "axios";
import {ListItem} from "react-native-elements";
import {createAppContainer, createStackNavigator} from "react-navigation";
import AppConfig from "../../AppConfig";
import Keys from "../../data/Constants/Storage";
import PronosticsDetailsScreen from "../../screens/PronosticsDetailsScreen";
class MontanteTab extends Component {
state = {
errors: null,
isLoading: true,
pronostics: [],
};
async componentDidMount() {
const isConnected = true;
if (isConnected) {
await this.loadPronostics();
}
try {
this.setState({pronostics: JSON.parse(await AsyncStorage.getItem(Keys.pronosticsMontante))});
} catch (error) {
console.log(error);
}
}
loadPronostics() {
this.setState({isLoading: true, error: null});
return axios.get(AppConfig.apiUrl + 'montante').then(async response => {
await AsyncStorage.setItem(Keys.pronosticsMontante, JSON.stringify(this.state.pronostics));
this.setState({isLoading: false});
}).catch(error => {
this.setState({isLoading: false, error: error.response});
console.log(error);
});
}
render() {
if (this.state.isLoading === true) {
return (
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return (
<View>
<ScrollView>
<View>
<FlatList
data={this.state.pronostics}
keyExtractor={(item, index) => index.toString()}
renderItem={({item}) => (
<ListItem
key={item.id}
roundAvatar
badge={{
value: item.statut,
textStyle: {color: '#fff'},
containerStyle: {marginRight: 0, backgroundColor: item.couleur}
}}
avatar={<Image
source={{uri: AppConfig.imagesPronosticsUrl + item.image}}
style={{borderRadius: 50, height: 50, width: 50}}/>}
title={item.competition}
subtitle={item.equipe_domicile + ' - ' + item.equipe_exterieur}
onPress={() => this.props.navigation.navigate('PronosticsDetails', {
item,
})}
/>
)}
/>
</View>
</ScrollView>
</View>
);
}
}
You can use React Native AsyncStorage for storing data to local storage of the device.
import { AsyncStorage } from 'react-native'
Use this to save data
AsyncStorage.setItem('key', 'value');
AsyncStorage accepts value as an only string, so you may need to use stringify() before setting the value to AsyncStorage
And to retrieve data use
AsyncStorage.getItem('key');
Code:
const KEY = 'USER_DATA'
let keyValue = { name: yogi }
AsyncStorage.setItem(KEY,keyValue);
AsyncStorage.getItem(KEY).then(asyncStorageRes => {
console.log(JSON.parse(asyncStorageRes))
});
As this is a React Native project, I think AsyncStorage is what you're looking for. You can set the value in your empty setState callback in componentDidMount. If you only need to store the data at the end of a session, you can use AppState and set the value when nextState is background or inactive.
Use AsyncStorage.getItem() when AppState or nextState is active.
https://facebook.github.io/react-native/docs/appstate
https://facebook.github.io/react-native/docs/asyncstorage
Its depend on how frequently your listing data change,
if listing data is constant then you can store API response in local storage. and then display list data from local storage.
If listing data changing frequently, still you can use local storage. store data in local storage on API response.
On next time page load show data from local storage and also make API call to get latest data and on API response display data to list and also update in local storage.
Using this way user will not have to wait for API response.
For Storing Data use can use javascript syntax localStorage.setItem('key', 'apiresponse') and localStorage.getItem('key')
OR
can create Service class which will store API response in object, which can be also use in other files.

React Native/Redux - Can't access Redux store

I'm trying to access two parts of my Redux store within a React Native component that I'm working on and for some reason, probably something simple, I can't get things working.
I'm passing the orderID as a property to the component and then I want to retrieve the appropriate order details from the Redux store: orders[orderID] but when trying to assign the local variable:
const order = this.props.orders[orderID];
I'm getting the error: Cannot read property 'orders' of undefined, i.e.: for some reason the orders part of the Redux store appears to not have connected to the component props.
Code is as follows:
import React from 'react';
import { connect } from 'react-redux';
import {
View,
Text
} from 'react-native';
import Status from '../Status';
import Card from './Card';
import CardSection from './CardSection';
const OrderDetail = ({ orderID }) => {
const order = this.props.orders[orderID];
const {
id,
status,
gross_price,
currency_symbol,
bookings
} = order;
return (
<Card>
<CardSection>
<View style={styles.headerContentStyle}>
<View style={styles.bookingIdHeaderContainerStyle}>
<Text style={styles.headerTextStyle}>Booking #{id}</Text>
</View>
<View style={styles.grossPriceHeaderContainerStyle}>
<Text style={styles.headerTextStyle}>{currency_symbol}{gross_price}</Text>
</View>
<View style={styles.statusHeaderContainerStyle}>
<Status status={status} />
</View>
</View>
</CardSection>
<CardSection>
<View style={styles.orderListContentStyle}>
<Text>Booking #1234</Text>
</View>
</CardSection>
</Card>
);
};
const styles = {
headerContentStyle: {
flex: 1,
flexDirection: 'row',
alignItems: 'center'
},
headerTextStyle: {
fontSize: 18
},
bookingIdHeaderContainerStyle: {
flex: 5
},
grossPriceHeaderContainerStyle: {
flex: 2
},
statusHeaderContainerStyle: {
flex: 2
},
orderListContentStyle: {
}
};
const mapStateToProps = state => {
return ({
orders: state.orders,
bookings: state.bookings
});
};
export default connect(mapStateToProps)(OrderDetail);
Any suggestions?
OrderDetail is a stateless functional component, and functional components don't have a this keyword.
May be this is what you wanted:
const OrderDetail = (props) => {
const order = props.orders[props.orderID];
// ...

Categories