How do I loop an array in React Native - arrays

The RSS feed is parsed into an array, but the promblem is, the array doesn't loop, it only shows 1 item. How do I loop my Feeds array?
This is my code, I use react-native-rss-parser (https://www.npmjs.com/package/react-native-rss-parser):
class TNScreens extends React.Component {
state = {
feed: [],
title: []
};
componentDidMount() {
return fetch("https://vnexpress.net/rss/tin-moi-nhat.rss")
.then(response => response.text())
.then(responseData => rssParser.parse(responseData))
.then(rss => {
for (let i = 0; i < rss.items.length; i++) {
this.setState(prevState => ({
...prevState,
feed: rss.items[i],
title: rss.items[i].title
}));
}
});
}
render() {
const Feeds = ([
{
pic: {uri: ''},
title: Object.keys(this.state.title).map(i => this.state.title[i])
}
]);
return (
<SafeAreaView>
<ScrollView>
<Text h2 h2Style={styles.h2Style}>
Trang nhất
</Text>
<Text h4 h4Style={styles.h4Style}>
Cập nhật siêu nhanh
</Text>
<View>
{Feeds.map(({ pic, title }) => (
<Tile
imageSrc={pic}
height={200}
activeOpacity={0.9}
title={title}
titleNumberOfLines={1}
titleStyle={styles.title}
featured
key={title}
/>
))}
</View>
</ScrollView>
</SafeAreaView>
);
}
}
export default TNScreen;
UPDATE
console.log(rss) result:
Object {
"authors": Array [],
"categories": Array [],
"copyright": undefined,
"description": "VnExpress RSS",
"image": Object {
"description": undefined,
"height": undefined,
"title": "Tin nhanh VnExpress - Đọc báo, tin tức online 24h",
"url": "https://s.vnecdn.net/vnexpress/i/v20/logos/vne_logo_rss.png",
"width": undefined,
},
"items": Array [],
"itunes": Object {
"authors": Array [],
"block": undefined,
"categories": Array [],
"complete": undefined,
"explicit": undefined,
"image": undefined,
"newFeedUrl": undefined,
"owner": Object {
"email": undefined,
"name": undefined,
},
"subtitle": undefined,
"summary": undefined,
},
"language": undefined,
"lastPublished": "Sat, 30 Nov 2019 21:28:12 +0700",
"lastUpdated": undefined,
"links": Array [
Object {
"rel": "",
"url": "https://vnexpress.net/rss/tin-moi-nhat.rss",
},
],
"title": "Tin mới nhất - VnExpress RSS",
"type": "rss-v2",
}

There is a problem in your code in for loop you are just replacing the state with one value you are not copying the previous state. You will have to
this.setState(prevState => ({
...prevState,
feed: [...prevState.feed, rss.items[i]],
title: [...prevState, rss.items[i].title]
}));
But this is not the best practice because on every iteration your render will re-render so the best practice is
const feeds = rss.items.map(item => item);
const titles = rss.items.map(item => item.title);
this.setState({ feed: feeds, title:titles });

your this.state.x only save one item, change the code to the following:
and you should also change the get Data method, please do not setState in a loop
componentDidMount() {
return fetch("https://vnexpress.net/rss/tin-moi-nhat.rss")
.then(response => response.text())
.then(responseData => rssParser.parse(responseData))
.then(rss => {
let copyRess = []
let copyTitle = []
for (let i = 0; i < rss.items.length; i++) {
copyRess.push(rss.items[i]);
copyTitle.push(rss.items[i].title)
}
this.setState(prevState => ({
...prevState,
feed: copuRess,
title: copyTitle
}));
});
}
render() {
const Feeds = []
this.state.title.map(element => {
Feeds.push({pic:"",title:element})
})
....

Related

How to access certain element of nested objects in react

I'm struggling to take certain value out of an API. I have no trouble mapping over the parts that I can immediately access using items.value, but when I can't get some of the more nested info. I'm specifically trying to access the value of "quantity" inside of pricing.
Here's my code
import "./StoreDisplay.css"
class StoreDisplay extends Component {
constructor(props) {
super(props)
this.state = {
error: undefined,
isLoaded: false,
items: []
}
}
componentDidMount() {
this.getData();
}
getData() {
fetch(url)
.then((res) => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result,
});
console.log(result)
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
);
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div id = "storeDisplay">
<ul className = "container">
{items.map(item => (
<li key = {item.title}>
<div className = "bundleName"> {item.title} {item.pricing.quantity}</div><img src = {item.asset} className = "img"></img>
</li>
))}
</ul>
</div>
);
}
}
}
Sample part of JSON from API:
[
{
"title": "100-Pack Bundle",
"desc": "",
"tag": "",
"purchaseLimit": 1,
"isAvailable": true,
"expireTimestamp": 1662538288,
"shopType": "specials",
"originalPrice": 10500,
"pricing": [
{
"ref": "Apex Coins",
"quantity": 6700
}
],
"content": [
{
"ref": "weapon_charm_charm_apex_asset_v22_misc_pathfinderemoji01",
"name": "MRVN Monitor",
"quantity": 1
},
{
"ref": "pack_cosmetic_rare",
"name": "Apex Pack",
"quantity": 100
}
],
"offerID": "220823_100-pack_bundle",
"asset": "https:\/\/shop-cdn.mozambiquehe.re\/dl_store_s14_0_bund_epic_100pack_a189.png"
},
It looks like item.pricing is actually an array of objects. From here you have a couple of choices, depending on what you want to do.
item.pricing will only ever have one element.
In this case, you can just take the first element:
<div className = "bundleName"> {item.title} {item.pricing[0].quantity}</div>
You want to list all the quantities
<div className = "bundleName"> {item.title} {item.pricing.map(pricing => pricing.quantity).join(" ")}</div>
or
<div className = "bundleName"> {item.title} {item.pricing.map(pricing => pricing.quantity).join(", ")}</div>
You want to have the sum of all quantities
<div className = "bundleName"> {item.title} {item.pricing.map(pricing => pricing.quantity).reduce((a, b) => a + b, 0)}</div>

How to pass object array as props to a custom component in react native?

I have fetched some data from an API as a JSON array in componentDidMount method as below.
componentDidMount() {
return fetch('http://..someAPI../product/')
.then(res => res.json())
.then(resJson => {
this.setState({
isLoading: false,
dataSource: resJson,
});
var objects = this.state.dataSource;
for (var i = 0; i < objects.length; i++) {
console.log('Item Name: ' + objects[i].productName);
}
})
.catch(err => {
console.log(err);
});
}
In here I get console.log output as I want. Now I want to pass the array in a loop as a prop to a custom component, but it gives error.
My render method looks like this
return (
<View>
<Content>
{this.state.dataSource.map(item => {
<Product Name={item.productName} price={item.price}/>;
})}
</Content>
</View>
);
My original Json object looks like this
[
{
"category": [
"Food",
"Bread",
"Bun"
],
"_id": "1",
"productName": "Sausage bun",
"price": 70,
"details": "test product",
},
{
"category": [
"Food",
"Bread",
"Bun"
],
"_id": "2",
"productName": "Fish Pastry",
"price": 50,
"details": "test product",
}
]
I want to pass these data to display the products as a loop. How can I do this? Thank you in advance!
Since data loading is asynchronous you probably have uninitialised state.
As a safer coding practice you could something like
{this.state.dataSource && this.state.dataSource.map(item => {
return <Product Name={item.productName} price={item.price}/>;
})}
Depending on your webpack configuration , you can also use optional chaining https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
{this.state?.dataSource?.map(item => {
<Product Name={item.productName} price={item.price}/>;
})}
Also,
initialize your state
this.state = {
dataSource: []
}

How to make check in flat list if data is not coming in React Native

I am trying to perform checks if the data is not coming in the flat list form the server in my case if data is coming it is working perfectly but when there is no data it is showing error here is my code
this is my flat list now i want to perform checks on it...
<FlatList
data={this.state.fetchJobs}
keyExtractor={(a, b) => b.toString()}
renderItem={({ item }) => (
<TouchableOpacity
activeOpacity={0.9}
onPress={() =>
this.props.navigation.navigate("DetailJobScreen", {
job_id: item.job_id
})
}
>
<CompleteJobLayout
Completejobname={`${entities.decode(item.employer_name)}`}
featuredCompleteJobColor={`${entities.decode(
item.featured_color
)}`}
imageUriCompleteJobfeatured={{ uri: `${item.featured_url}` }}
Completejobtitle={`${entities.decode(item.project_title)}`}
jobflagimageUri={{ uri: `${item.location.flag}` }}
Completejoblevel={`${entities.decode(
item.project_level.level_title
)}`}
Completejobcountry={`${entities.decode(
item.location._country
)}`}
Completejobrate={`${entities.decode(item.project_cost)}`}
fav_job_user_id={item.job_id}
Fav_Color={`${entities.decode(item.favorit)}`}
Completejobduration={`${entities.decode(
item.project_duration
)}`}
/>
</TouchableOpacity>
)}
/>
here is the response when data is comming...
[
{
"favorit": "",
"featured_url": "",
"featured_color": "",
"location": {
"_country": "India",
"flag": "https://amentotech.com/projects/api_workreap/wp-content/uploads/2019/03/img-03-2.png"
},
"job_id": 178,
"job_link": "https://amentotech.com/projects/api_workreap/project/forest-technology-professor/",
"_is_verified": "yes",
"project_level": {
"level_title": "Medium Level",
"level_sign": 0
},
"project_type": "Fixed",
"project_duration": "01 to 03 months",
"project_cost": "$6,399.00",
"attanchents": [
{
"document_name": "WordPress customization",
"file_size": "85.84 KB",
"filetype": {
"ext": "pdf",
"type": "application/pdf"
},
"extension": "",
"url": "https://amentotech.com/projects/worktern/wp-content/uploads/2019/03/WordPress-customization.pdf"
},
{
"document_name": "How to run mysql command in database",
"file_size": "16.06 KB",
"filetype": {
"ext": "docx",
"type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
},
"extension": "",
"url": "https://amentotech.com/projects/worktern/wp-content/uploads/2019/03/How-to-run-mysql-command-in-database.docx"
}
],
"skills": [
{
"skill_link": "https://amentotech.com/projects/api_workreap/skill/c/",
"skill_name": "C++"
},
{
"skill_link": "https://amentotech.com/projects/api_workreap/skill/graphic-design/",
"skill_name": "Graphic Design"
},
{
"skill_link": "https://amentotech.com/projects/api_workreap/skill/html-5/",
"skill_name": "HTML 5"
},
{
"skill_link": "https://amentotech.com/projects/api_workreap/skill/seo/",
"skill_name": "SEO"
}
],
"employer_name": "Steven Ford",
"project_title": "Forest Technology Professor",
"project_content": "Some Data"
}]
and this is the response when there is no data available...
[
{
"type": "error",
"message": "Some error occur, please try again later"
}
]
and this is my function where i am fetching data...
fetchCompleteJobData = async () => {
const { params } = this.props.navigation.state;
const response = await fetch(
"https:...//listing/get_jobs?listing_type=company&company_id=" +
params.employ_id
);
const json = await response.json();
this.setState({ fetchJobs: json, isLoading: false });
console.log('These are my jobs'+JSON.stringify(fetchJobs))
};
Kindly tell me how can i make check if there is no data show no data message
You can check if response is of type error and set an empty array in your component's state.
fetchCompleteJobData = async () => {
//... your code to fetch data
const json = await response.json();
if(Array.isArray(json) && json[0] && json[0].type && json[0].type === 'error') {
this.setState({ fetchJobs:[], isLoading: false }); // empty data set
} else {
this.setState({ fetchJobs: json, isLoading: false });
}
};
{
this.state.fetchJobs.length ? (
<FlatList
...
/>
) : (
<View>
...
</View>
)
}

How to use FetchAPI nested Arrays of same object

I am trying to show menu where it can have parent child relationship, with flat structure it is working fine but with nested objects not able to do it.
The below is the JSON and reactJS code.
JSON -
{
"data": [
{
"to": "#a-link",
"icon": "spinner",
"label": "User Maintenance"
},
{
"content": [
{
"to": "#b1-link",
"icon": "apple",
"label": "System Controls"
},
{
"to": "#b2-link",
"icon": "user",
"label": "User Maintenance"
}
],
"icon": "gear",
"label": "System Preferences"
},
{
"to": "#c-link",
"icon": "gear",
"label": "Configuration"
}
]
}
ReactJS code -
export default class MenuComponent extends Component {
constructor() {
super();
this.state = {}
}
componentDidMount(){
fetch('http://localhost:8084/Accounting/rest/v1/company/menu?request=abc')
.then(response => response.json())
.then(parsedJSON => parsedJSON.data.map(menu => (
{
to: `${menu.to}`,
icon: `${menu.icon}`,
label: `${menu.label}`
// content: `${menu.content}`
}
)))
.then(content => this.setState({
content
}))
}
render() {
console.log('333');
console.log(this.state.content);
return (
<MetisMenu content={this.state.content} activeLinkFromLocation />
)
}
}
In JSON you can see the 'System Preference' has nested content.
Try this code
class MenuComponent extends Component {
constructor() {
super();
this.state = {
content : []
}
}
componentDidMount(){
fetch('http://localhost:8084/Accounting/rest/v1/company/menu?request=abc')
.then(response => response.json())
.then(parsedJSON => parsedJSON.data.map(menu => (
{
to: `${menu.to}`,
icon: `${menu.icon}`,
label: `${menu.label}`
// content: `${menu.content}`
}
)))
.then(content => this.setState({
content
}))
}
render() {
const {content} = this.state
if(content === undefined){
return <div>Content not found</div>;
}
if(content.length === 0){
return <div>Loading</div>;
}
return (
<MetisMenu content={content} activeLinkFromLocation />
)
}
}
export default MenuComponent

Rendering a nested object state

This problem is giving me a huge headache so any help is welcome :)
In this component, I'm making 2 axios calls to different APIs: one for freegeoip and one for openweathermap. I'm storing the data in the currentCity state, which is an object with 2 keys, location and weather. The idea is that the app detects your current location (using freegeoip) and renders location name and weather data (using openweathermap).
I'm positive it's storing the state properly as console logs have confirmed. I can render the location data for currentCity state, but can't seem to render the weather data for currentCity state.
renderCurrentCity(city) {
console.log('state3:', this.state.currentCity);
console.log([city.weather.main]);
return(
<div>
<li>{city.location.city}, {city.location.country_name}</li> // Working
<li>{city.weather.main.temp}</li> // Not working
</div>
)
}
The console error I get:
Uncaught (in promise) TypeError: Cannot read property '_currentElement' of null
currentCity.location JSON:
{
"ip": // hidden,
"country_code": "FR",
"country_name": "France",
"region_code": "GES",
"region_name": "Grand-Est",
"city": "Reims",
"zip_code": "",
"time_zone": "Europe/Paris",
"latitude": 49.25,
"longitude": 4.0333,
"metro_code": 0
}
currentCity.weather JSON:
{
"coord": {
"lon": 4.03,
"lat": 49.25
},
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}
],
"base": "stations",
"main": {
"temp": 283.15,
"pressure": 1011,
"humidity": 43,
"temp_min": 283.15,
"temp_max": 283.15
},
"visibility": 10000,
"wind": {
"speed": 3.1,
"deg": 350
},
"clouds": {
"all": 0
},
"dt": 1493127000,
"sys": {
"type": 1,
"id": 5604,
"message": 0.1534,
"country": "FR",
"sunrise": 1493094714,
"sunset": 1493146351
},
"id": 2984114,
"name": "Reims",
"cod": 200
}
Rest of code:
import React, { Component } from 'react';
import axios from 'axios';
import WeatherList from './weatherlist';
import SearchBar from './searchbar';
const API_KEY = '95108d63b7f0cf597d80c6d17c8010e0';
const ROOT_URL = 'http://api.openweathermap.org/data/2.5/weather?'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
cities: [],
errors: '',
currentCity: {
location: {},
weather: {}
}
};
this.currentCity();
this.renderCurrentCity = this.renderCurrentCity.bind(this);
}
citySearch(city) {
const url = `${ROOT_URL}&appid=${API_KEY}&q=${city}`;
axios.get(url)
.then(response => {
const citiesArr = this.state.cities.slice();
this.setState({
cities: [response.data, ...citiesArr],
errors: null
});
})
.catch(error => {
this.setState({
errors: 'City not found'
})
})
}
currentCity() {
var city;
var country;
axios.get('http://freegeoip.net/json/')
.then(response => {
const lat = response.data.latitude;
const lon = response.data.longitude;
city = response.data.city;
country = response.data.country_name;
const url = `${ROOT_URL}&appid=${API_KEY}&lat=${lat}&lon=${lon}`;
const state = this.state.currentCity;
console.log('state1:',state);
this.setState({
currentCity: { ...state, location: response.data }
});
console.log(url);
axios.get(url)
.then(city => {
const state = this.state.currentCity;
console.log('state2:', state);
this.setState({
currentCity: { ...state, weather: city.data }
});
})
})
}
renderCurrentCity(city) {
console.log('state3:', this.state.currentCity);
console.log([city.weather.main]);
return(
<div>
<li>{city.location.city}, {city.location.country_name}</li>
<li>{city.weather.main.temp}</li>
</div>
)
}
render() {
return (
<div className={this.state.cities == false ? 'search': 'search-up'}>
<h1>What's the weather today?</h1>
<ul className='list-unstyled text-center'>
{this.renderCurrentCity(this.state.currentCity)}
</ul>
<SearchBar
onSearchSubmit={this.citySearch.bind(this)}
errors={this.state.errors} />
{this.state.cities == false ? null : <WeatherList cities={this.state.cities} />}
</div>
)
}
}
You are spreading your whole state when your receive the weather data:
this.setState({
currentCity: { ...state, weather: city.data }
});
it should be:
this.setState({
currentCity: { ...state.currentCity, weather: city.data }
});

Resources