How to fetch complex json into React Native Flatlist? - react-native

I'm trying to fetch an API from a news API however the format is a little hard for me to extract the data from. I have tried to parse the json into an array but still wasn't able to fetch the data into a flatlist. May I have any suggestion to overcome this problem? thanks for any help. I've built this on expo which can be tested on the following link.
The following is the API class:
import React, {Component} from 'react';
import {Text, ActivityIndicator, FlatList} from 'react-native';
export default class API extends Component{
constructor(props){
super(props);
this.state = {
isLoading: true,
data: null
}
}
componentDidMount(){
fetch('https://newsapi.org/v2/top-headlines?country=my&category=sports&apiKey=73e8cdd9f6be475cb4a2d128bae3650c')
.then((response) => response.json())
.then((responseJson) => {
//tried to simplify the json(I'm not sure whether its right)
//var parsedjson = JSON.parse(responseJson);
//var myarray = parsedjson.articles;
this.setState({
isLoading: false,
data: responseJson//myarray,
})
})
.catch((error) => {
console.error(error);
});
}
_renderItem = ({item, index}) =>{
return(
//I think here's the problem. I've tried to use {item.articles.title}
<Text>{item.title}</Text>
)
}
render(){
if(this.state.isLoading){
return(
<ActivityIndicator style={{marginTop: 250}} size="large" color='white'/>
)
}else{
let {data, isLoading} = this.state;
return(
<FlatList
data={data}
renderItem={this._renderItem}
keyExtractor={(item,index)=> index.toString()}
/>
)
}
}
}
Using the same way, I managed to fetch API which has a format like
[
{
"id": "1",
"title": "GG",
"body": "the body here",
"image": "image link",
"link": null
}]
but now its not working when using json with format like this:
{
"status": "ok",
"totalResults": 38,
"articles": [
{
"source": {
"id": "the-washington-post",
"name": "The Washington Post"
},
"author": "Rachel Lerman, Cat Zakrzewski, Heather Kelly",
"title": "Apple"
}
]
}

In your componentDidMount, you have
componentDidMount(){
fetch('https://newsapi.org/v2/top-headlines?country=my&category=sports&apiKey=73e8cdd9f6be475cb4a2d128bae3650c')
.then((response) => response.json())
.then((responseJson) => {
//var parsedjson = JSON.parse(responseJson);
// you don't need to parse the json here. It's already a JSON object.
this.setState({
isLoading: false,
data: responseJson, // here you can do either responseJson or responseJson.articles.
})
})
.catch((error) => {
console.error(error);
});
}
You don't need to use JSON.parse() on a JSON. You can read more about JSON parse at MDN
Now, in your FlatList, you have,
<FlatList
data={data}
renderItem={this._renderItem}
keyExtractor={(item,index)=> index.toString()}
/>
In your data prop of Flatlist, change the data to either data.articles or just data depending on the state you have set to your data.
If you have used,
this.setState({
isLoading: false,
data: responseJson,
})
You will have to make the data prop of FlatList like below,
<FlatList
data={data.articles}
renderItem={this._renderItem}
keyExtractor={(item,index)=> index.toString()}
/>
Or if you have set the data state as,
this.setState({
isLoading: false,
data: responseJson.articles,
})
you can simply keep the FlatList as it is now.
Now on your _renderItem,
_renderItem = ({item, index}) =>{
return(
<Text>{item.title}</Text>
)
}
This is how it should be. You don't need to use {item.articles.title}, as you have already supplied the articles array to your FlatList component.

what you want to fetch from the given json, if u have multiple date in json then you have to pass positions.
you have to write like this
import jsonObject from 'path'
then if u want to get articles array then write
jsonObject.articles etc

Related

Display datas with Axios (React Native)

I am trying to display data that I fetched with Axios. They came as an array. Because of this I cant show them. What should I do?
Here is my fetch code
componentDidMount() {
axios.post('http://192.168.1.106:80/partner_project_backend/project_list.php')
.then((response) => {
console.log(response.data)
})
.catch((error) => {
console.error(error);
});
}
Here is my console.log
I'm guessing you are getting the API response correctly and your only intention is to display the data in your application. If so, you could use the FlatList component from React Native
import React from 'react';
import { FlatList, Text } from 'react-native';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
componentDidMount() {
axios.get('http://192.168.1.106:80/partner_project_backend/project_list.php')
.then((response) => {
this.setState({ data: response.data });
})
.catch((error) => {
console.error(error);
});
}
render() {
return (
<FlatList
data={data}
renderItem={({ item }) => (
<Text>{item.name}</Text> // render your view here
)}
keyExtractor={item => item.id}
/>
);
}
}
React more about FlatList at https://reactnative.dev/docs/flatlist
To fetch data you have to use get method NOT post
this.state ={ data : null }
componentDidMount(){
axios.get('http://192.168.1.106:80/partner_project_backend/project_list.php')
.then((response) => {
this.setState({ data : response.data })
})
.catch((error) => {
console.error(error);
});
}

React Native: How to change inputfield to selected item

So what I'm trying to do is fetching data from an API (works well), that has this autocomplete function.
Link to example: https://autocomplete.aws.dk/
Link to the guide: https://autocomplete.aws.dk/guide2.html
What is hard for me, is that the guide is HTML, and this is suppose to work in React Native.
So far I made an input field, that can detect when writing minimum two letters will show a list of addresses.
What I want is when the address is clicked, it takes that value and places it in the input field.
Heres my code:
The API fetch:
import React from "react";
import url from "./url";
export default class DawaFetch extends React.Component {
static defaultProps = {
options: {},
minCharacters: 2,
};
state = {
value: "",
suggestions: [],
};
handleChange = ({ target: { value } }) => {
this.setState({ value });
if (this.props.minCharacters <= value.length) this._fetch(value);
};
_fetch = (value) => {
fetch(
url("https://dawa.aws.dk/adresser/autocomplete", {
q: value,
["per_side"]: 100,
...this.props.options,
}),
{
method: "GET",
headers: {
"Accept-Encoding": "gzip, deflate",
},
}
)
.then((response) => response.json())
.then((json) => this.setState({ suggestions: json }))
.catch((err) => console.error("parsing failed", err));
};
render = () =>
this.props.children({ ...this.state, handleChange: this.handleChange });
}
And here is my view:
<DawaFetch>
{({ value, suggestions, handleChange }) => {
console.log(suggestions);
return (
<View>
<CustomInputs
type="text"
value={value}
onChange={handleChange}
/>
{suggestions.map((suggestion) => (
<TouchableOpacity>
<NormalText key={suggestion.adresse.id}>{suggestion.tekst}</NormalText>
</TouchableOpacity>
))}
</View>
);
}}
</DawaFetch>
Tried different solutions by making it a FlatList with renderItem, and making an onPress function, but I could never make it work.
Hopefully someone can guide me in the right direction, I might been overthinking this.
React-Native TextInput onChange value is not available inside the target as it's available in HTML, Remove target from handleChange function like below, also it's not onChange it's onChangeText in TextInput.
handleChange = (value) => {
this.setState({ value });
if (this.props.minCharacters <= value.length) this._fetch(value);
};
You can achieve your desired functionality in a very simple manner.
Add this to your DawaFetch class.
OnItemSelection=(address)=>{
this.setState({value: address})
}
Add this to your render Function
render = () =>
this.props.children({ ...this.state, handleChange: this.handleChange, OnItemSelection: this.OnItemSelection });
}
Then make these changes in your DawaFetch component
<DawaFetch>
{({ value, suggestions, handleChange, OnItemSelection }) => {
console.log(suggestions);
return (
<View>
<CustomInputs
type="text"
value={value}
onChangeText={handleChange}
/>
{suggestions.map((suggestion) => (
<TouchableOpacity onPress={()=> OnItemSelection(suggestion.adresse)}>
<NormalText key={suggestion.adresse.id}>{suggestion.tekst}</NormalText>
</TouchableOpacity>
))}
</View>
);
}}
</DawaFetch>
Edit:Here is Snack having solution
https://snack.expo.io/#waheed25/bad-raisins

Why isn't flatlist not able to map through and display the data?

I am using Zomato API to get the list of restaurants, data is in the form of the array which has object restaurants in which there are different restaurant objects and then their name and other details.
It's my first time using a flat List and I am not able to display this data.
Goal: Use the search bar to display the list of restaurants in the city using flatlist.
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { SearchBar } from 'react-native-elements';
import { FlatList } from 'react-native-gesture-handler';
class Main extends Component {
constructor(props) {
super(props);
this.state = { search: '', data: [] };
}
componentDidMount() {
fetch('https://developers.zomato.com/api/v2.1/search', {
method: 'GET',
headers: {
'user-key': '999999999999999999999999999'
},
params: JSON.stringify({
entity_type: 'city',
q: {this.state.search}
}),
}).then((response) => response.json())
.then((responseJson) => { return this.setState({ data: responseJson.restaurants }) })
.catch((error) => { console.warn(error) }
);
}
render() {
let data = this.state.data;
let name = data.map(p => p.restaurant.name)
console.warn("Check Data", name)
return (
<View>
<SearchBar
round
searchIcon={{ size: 24 }}
placeholder='Search'
onChangeText={search => { this.setState({ search }) }}
value={this.state.search}
/>
//Using this method to display the data if any
{name.length != 0 ?
<FlatList
data={name}
keyExtractor={(x, i) => x + i}
renderItem={({ name }) => <Text>{name}-DATA</Text>}
/>
: <View style={{height:"100%", width:"100%", alignItems:"center",
justifyContent:"center"}}>
<Text>No data found</Text>
</View>
}
</View>
);
}
}
export default Main;
Maybe the way I declared state is wrong, or maybe the way I'm storing the data in the state is wrong.
I got the names of the restaurant in the console.warn successfully.
Without your users-key I can't surely understand what is your api results.
Here
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { SearchBar } from 'react-native-elements';
import { FlatList } from 'react-native-gesture-handler';
class Main extends Component {
constructor(props) {
super(props);
this.state = { search: '', data: [] };
}
componentDidMount() {
fetch('http://phplaravel-325095-1114213.cloudwaysapps.com/api/shop/shop/', {
method: 'GET',
}).then((response) => response.json())
.then((responseJson) => { return this.setState({ data: responseJson }) })
.catch((error) => { alert(error) }
);
}
render() {
let data = this.state.data;
return (
<View>
<SearchBar
round
searchIcon={{ size: 24 }}
placeholder='Search'
onChangeText={search => { this.setState({ search }) }}
value={this.state.search}
/>
{data.length != 0 ?
<FlatList
data={data}
keyExtractor={(x, i) => x + i}
renderItem={({ item }) => <Text>{item.name}-DATA</Text>}
/>
: <View style={{height:"100%", width:"100%", alignItems:"center",
justifyContent:"center"}}>
<Text>No data found</Text>
</View>
}
</View>
);
}
}
export default Main;
This is a working code with another api call just add your api call instead on mine.. This is working properly. I guess you are just messing with your data.
Try replacing the renderItem from FlatList to
renderItem={({ item }) => <Text>{item}-DATA</Text>}
Also, replace the condition to use double equals like name.length !== 0
Check the url link properly.
https://developers.zomato.com/api/v2.1/search/999999999999999999999999999
Just check it on web browser it is showing message : The requested url was not found
It means we are not getting any data from this URL.
That why we are not able to map any data.

How do I access this rss variable inside my fetch method in React Native?

I'm trying to use react-native-rss-parser (https://www.npmjs.com/package/react-native-rss-parser) to parse my RSS feed and display it on a card but I don't know how to access the rss variable.
fetchRSSFeed() {
return fetch('http://www.nasa.gov/rss/dyn/breaking_news.rss')
.then((response) => response.text())
.then((responseData) => rssParser.parse(responseData))
.then((rss) => { console.log(rss.title) })
}
render() {
{this.fetchRSSFeed()}
return (
<SafeAreaView style={styles.container}>
<Swiper
cards={HomeScreenPics}
renderCard={Card}
infinite
backgroundColor="white"
cardHorizontalMargin={0}
stackSize={2}
/>
</SafeAreaView>
)
}
}
HomeScreenPics = [{
pic: require('../assets/images/news.jpg'),
title: rss.title
}]
console.log(rss.title) works fine. It logs out the RSS feed title but I'm trying to access the rss varible outside the fetch method, I want to parse it into my HomeScreenPics array, but it keeps showing the error: Can't find variable rss
If you want to access the rss variable and pass it to the render function, all you have to do is to use the state that react provides you.
Example:
state = {
feed: {}
}
fetchRSSFeed() {
return fetch('http://www.nasa.gov/rss/dyn/breaking_news.rss')
.then((response) => response.text())
.then((responseData) => rssParser.parse(responseData))
.then((rss) => {
this.setState(prevState => ({
...prevState,
feed: rss
}));
})
}
render() {
{this.fetchRSSFeed()}
return (
<SafeAreaView style={styles.container}>
<Swiper
cards={HomeScreenPics}
renderCard={Card}
infinite
backgroundColor="white"
cardHorizontalMargin={0}
stackSize={2}
/>
<Text>{this.state.feed.title}</Text>
</SafeAreaView>
)
}
}
You can access the response object with the variable this.state.feedin any function.
I recommend you to start from the official documentation: [https://facebook.github.io/react-native/docs/state]
Friendly.
I am actually facing the same issue as you had. xarhsasi answers works like a charm.
Bear in mind that you can avoid calling the function each time since you are willing to render it once, just at the beginning.
I strongly recommend you to add it into a componentDidMount(), like so
constructor(props) {
super(props);
this.state = {
isLoading: true,
feed: {}
}
}
componentDidMount() {
return fetch('http://www.nasa.gov/rss/dyn/breaking_news.rss')
.then((response) => response.text())
.then((responseData) => rssParser.parse(responseData))
.then((rss) => {
this.setState({
isLoading: false,
feed: rss
});
});
}
Then, you only need to call the state like xarhsasi told you with this.state.feed.title, for example.
Best regards,

How to call fetch() inside renderItem on FlatList?

I have been unable to solve this so far, I hope someone from here can help me :)
The situation is as following:
I load a list of users from a department using an API which returns it as JSON (this works).
For each user in the JSON file, I have to fetch another JSON file containing sensor data (this does not work).
I am in fact capable of getting the JSON data from the getStatus() function, but it is not correct. Because, when the FlatList is rendered, the data still has not been fetched, but on refresh, calling fetchUsers(), the sensor data shows up, but it shows the same sensor data on all users and not their own specific sensor data.
At the moment I have made it spit out what ever JSON it receives in a Text element in order to see what was returned...
I am not allowed to upload pictures here, but I have made an album on Imgur which contains images of the application to help explain the issue: https://imgur.com/a/5XLpR
export default class SensorData extends Component {
constructor(props) {
super(props);
this.stats = null;
this.state = {
isLoading: true,
error: false,
userDataSource: [],
refreshing: false,
time: 30,
navigation: props.navigation,
};
}
componentDidMount() {
this.fetchUsers();
}
fetchUsers(){
return fetch('http://url-to-the-json/json/patients.json')
.then((response) => response.json())
.then((response) => {
this.setState({
isLoading: false,
error: false,
userDataSource: response,
refreshing: false,
time: 30,
}, function () {
});
})
.catch((error) => {
this.setState({
isLoading: false,
error: true
})
});
}
getStatus(patientId) {
fetch("http://url-to-the-json/json/status/" + patientId + ".json")
.then((response) => response.json())
.then((responseJson) => {
this.stats = responseJson;
})
.catch((error) => {
Alert.alert("Error");
});
return this.stats;
};
renderItem(item, index) {
var x = index % 2 === 0;
status = this.getStatus(item.patientId);
return (
<View style={x ? styles.rowEven : styles.rowOdd}>
<TouchableOpacity style={styles.rowName} onPress={this.handlePress.bind(this, item)}>
<Text style={styles.rowNameText}>{item.firstname} {item.lastname}</Text>
</TouchableOpacity>
<Text>{JSON.stringify(status)}</Text>
</View>
)
}
render() {
return (
<View>
<View style={styles.reloadTimer}>
<Text style={styles.timerText}>Reloading in {this.state.time} seconds.</Text>
</View>
<View style={styles.listView}>
<FlatList
data={this.state.userDataSource}
renderItem={({ item, index }) => this.renderItem(item, index)}
keyExtractor={item => item.patientId}
refreshing={this.state.refreshing}
onRefresh={this.handleRefresh}
ItemSeparatorComponent={this.renderSeparator}
/>
</View>
</View>
);
}
}
The variable status is the one in question.
I hope I formulated the question in an understandable manner.
The users JSON file looks like this:
{
"patientId": "ec276ca9-f9ab-429b-b34e-23fcf448d714",
"firstname": "Julie",
"lastname": "Nielsen",
"birthDate": "1930-01-01T00:00:00Z",
"departmentId": "709f59ae-67fe-447c-bed3-7b5912703861",
"patientNumber": null,
"entryDate": null,
"dischargeDate": null,
"editedOn": null,
"editedBy": null
}
The sensor data JSON file looks like this:
{
"status": {
"in_bed": false,
"in_room": true,
"clean_diaper": true
}
}
You need to store the result of getStatus in component state like you do with the patients JSON. Assuming you have a "stats" object in your state that maps a patient to their stats, you can do:
getStatus(patientId) {
fetch("http://url-to-the-json/json/status/" + patientId + ".json")
.then((response) => response.json())
.then((responseJson) => {
let stats = Object.assign({}, this.state.stats);
stats[patientId] = responseJson;
this.setState({ stats: stats });
})
.catch((error) => {
Alert.alert("Error");
});
};
Then, in the renderItem function, you can render the stats from state, or render a placeholder text if the stats haven't been loaded yet.
Also, you should not make network requests inside a render function, since they can be called quite often and multiple times for the same component. Instead, you should look into the FlatList API and the callbacks for changes in visibility.
Hope this helps...