Render JSON data from API call in react - reactjs

Working on an app using the google maps API for geolocation with Reactjs. My aim right now is to simply render the entire JSON data to the window (will be used later). No errors, but nothing is rendering to the page. Am I trying to access the data inccorrectly?
class App extends Component {
constructor () {
super();
this.state = {
isLoaded: false,
results: {}
};
}
componentDidMount() {
fetch(geo_url)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
results: result.results
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const {error, isLoaded, results} = this.state;
if (error) {
return <div>Error: {error.message} </div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className="App">
Location Data:
{results.geometry}
</div>
);
}
}
}
Below is a sample of the JSON i'm trying to access:
{
"results": [
{
"address_components": [
{
"long_name": "1600",
"short_name": "1600",
"types": [
"street_number"
]
},
{
"long_name": "Amphitheatre Parkway",
"short_name": "Amphitheatre Pkwy",
"types": [
"route"
]
},
{
"long_name": "Mountain View",
"short_name": "Mountain View",
"types": [
"locality",
"political"
]
},
{
"long_name": "Santa Clara County",
"short_name": "Santa Clara County",
"types": [
"administrative_area_level_2",
"political"
]
},
{
"long_name": "California",
"short_name": "CA",
"types": [
"administrative_area_level_1",
"political"
]
},
{
"long_name": "United States",
"short_name": "US",
"types": [
"country",
"political"
]
},
{
"long_name": "94043",
"short_name": "94043",
"types": [
"postal_code"
]
}
],
"formatted_address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
"geometry": {
"location": {
"lat": 37.422617,
"lng": -122.0853839
},
"location_type": "ROOFTOP",
"viewport": {
"northeast": {
"lat": 37.4239659802915,
"lng": -122.0840349197085
},
"southwest": {
"lat": 37.4212680197085,
"lng": -122.0867328802915
}
}
},
"place_id": "ChIJ2eUgeAK6j4ARbn5u_wAGqWA",
"plus_code": {
"compound_code": "CWF7+2R Mountain View, California, United States",
"global_code": "849VCWF7+2R"
},
"types": [
"street_address"
]
}
],
"status": "OK"
}

First render occurs before results are retrieved. Check in render() whether results exist already. If not, display a 'loading' message.
In addition to that, fix your handling of error while trying to retrieve data. You are setting a state.error variable which was not defined. Then, in render, display an error message if loading is done but there is an error.

First, you have to do :
<div className="App">
{this.state.results.geometry}
</div>
or
render() {
const {results} = this.state
return (
<div className="App">
{results.geometry}
</div>
);
}
}
But Like #Yossi saids, you result are not defined in you first render. That's why you have : "results not defined". You can use "lodash" to force your render. It's works even if I don't know if it's a good practice
You can test :
import _ from 'lodash';
render() {
const {results} = this.state
return (
{!_.isEmpty(results) &&
<div className="App">
{results.geometry}
</div>
}
);
}
It should be works :)
PS : sorry for my bad english ;)

You can set in state a key for error: false.
In componentDidMount its better to use then and catch for errors
componentDidMount() {
fetch(geo_url)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
results: result.results
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
).catch(error) {
this.setState({
isLoaded: true,
error
})
}
}

Related

I am trying to call Weather API using React and Axios I am trying to console.log the result but its saying the undefined... :(

When I am trying the console log the state its saying Undefined.. I also placed the JSON file.
I have posted the endpoint json file here. I believe there is an issue while hooking up json.
When I am trying the console log the state its saying Undefined.. I also placed the JSON file.
I have posted the endpoint json file here. I believe there is an issue while hooking up json.
class App extends Component {
state = {
content: [{ coord: "" }, { base: "" }]
};
componentDidMount() {
axios
.get(
"https://api.openweathermap.org/data/2.5/weather?q=berlin&appid=240ef553958220e0d857212bc790cd14"
)
.then(res => {
this.setState({
content: [
{
coord: res.data.coord
},
{ base: res.data.base }
]
});
});
}
render() {
console.log(this.state.content.coord);
return (
<div className="App center">
<h2 className="blue-text">Weather App</h2>
<div></div>
<Weather />
</div>
);
}
}
export default App;
JSON endpoint goes here....
{
"coord": {
"lon": 13.41,
"lat": 52.52
},
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04n"
}
],
"base": "stations",
"main": {
"temp": 276.88,
"feels_like": 268.47,
"temp_min": 275.37,
"temp_max": 278.15,
"pressure": 994,
"humidity": 80
},
"visibility": 10000,
"wind": {
"speed": 9.3,
"deg": 240,
"gust": 14.4
},
"clouds": {
"all": 75
},
"dt": 1580260557,
"sys": {
"type": 1,
"id": 1275,
"country": "DE",
"sunrise": 1580280826,
"sunset": 1580312685
},
"timezone": 3600,
"id": 2950159,
"name": "Berlin",
"cod": 200
}
As content is an array type you can access coord or base directly. Instead change it to an object or access it based on array index like this.
this.state.content[0].coord / this.state.content[1].base
If you change content to object type you can access coord or base directly as i did it here
sample code:
state = {
content: { coord: "", base: "" }
};
after request fetch you can update state something like this.
this.setState({
content: { coord: res.data.coord, base: res.data.base }
});
You can make your state look like below which make reading and accessing the data easier.
state = {
content: {
coord: "",
base: "",
},
}
and your setState like below:
this.setState({
content: {
coord: res.data.coord,
base: res.data.base
}
})

I need to do a React.js app that logs in into an API to get the session key from the current session using Axios

I apologize if it doesnt make much sense, I am new to stackoverflow and React
I already made the React app, my problem is that I dont understand how to login into an API and making a GET request to get the current session key.
I have tried following axios docs and fetch but the only thing I get is or Network error or a CORS error.
this is with axios
// class LoginForm extends React.Component {
// state = {
// users: []
// }
// componentDidMount() {
// const url = API_URL;
// axios.get(url)
// .then(res=> {
// const users = res.data;
// this.setState({users});
// })
// }
// render() {
// return (
// <div>{Object.keys(this.state.users).map(user => <h3>{user.skey}</h3> )}</div>
// )
// };
// }
this is with fetch
componentDidMount() {
fetch(API_URL)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result.items
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
this is the JSON from the API (I had altered content for security)
{
"skey": "lep8k7jcbtba2Hwlcf4ZGVtgbmwo8s56721",
"authenticated": false,
"silo": "demo",
"user": {
"uuid": "f205daa8-b838-41c7-984be",
"username": "guest",
"full_name": "Guest",
"email": "guest",
"groups": [
{
"uuid": "27e2e4f9-ebee-4ecca10151",
"name": "guest_user"
},
{
"uuid": "c354f1b5-ca702fe3",
"name": "public"
}
],
"roles": [
{
"uuid": "027a210b657f52b10dd4",
"name": "limited"
}
],
"permits": [
{
"uuid": "e1e896-c5bd-35494211374e",
"name": "collection.create.ccpUser"
},
{
"uuid": "0e4a0a9c-8cca9-4803da46d23d",
"name": "contribution.create.ccpArticle"
},
{
"uuid": "83f93b4dab-116dd29b19e3",
"name": "contribution.view.ccpComment"
},
{
"uuid": "b7401658-4509-98e28868748b",
"name": "view_pub_public"
},
{
"uuid": "0016447d-af2b-3c4dd0bcf55d",
"name": "ws.config.list"
},
{
"uuid": "0c776bcb-7656-6e15-9ecb2389ea6f",
"name": "ws.pubs"
},
{
"uuid": "4839a09b-5be-b119-3ee8281780e3",
"name": "ws.user.login"
}
]
},
"httpSession": "devtvowc4gmo8s5672",
"cmsVersion": "6.3p"
}
Wrap your res around parenthesis. Try this:
axios.get(url)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})

Map through Array object stored in state

Im trying to access data from an API and render the results. Im storing each object in a separate state and im trying to map through each state, however this throws the following Error.
My code is:
state = {
events: [],
items: [],
isLoading: true
}
// fetchData = () => {
componentDidMount() {
const url = 'http://www.mocky.io/v2/5c8673f0340000981789c0da'
axios.get(url).then(response => {
this.setState({ items: response.data, isLoading: false, events: response.data[0] })
console.log(this.state.events)
})
}
render() {
return(
<div>
<div>
<h1>26/2</h1>
<ul>
{ this.state.events.map(event => (<li>{event.activity}</li>)) }
</ul>
</div>
<div>
<h1>27/2</h1>
<ul>
</ul>
</div>
</div>
)
}
}
API structure:
[
{
"id": 1,
"activity": "lunch",
"startDate": "2019-02-26 12:00",
"endDate": "2019-02-26 13:00",
"location": "Lagerhuset"
},
{
"id": 2,
"activity": "meeting",
"startDate": "2019-02-26 22:00",
"endDate": "2019-02-27 07:00",
"location": "online"
},
{
"id": 3,
"activity": "meeting",
"startDate": "2019-02-26 10:00",
"endDate": "2019-02-26 12:00",
"location": "Lagerhuset"
}
]
Now im wondering if what I'm trying to achieve even is possible? And if so, what am I doing wrong? Thanks.
items contain the array of items. events just contain the first item which is an object. Hence the map fails.
Either use :
{this.state.items.map(event => (
<li>{event.activity}</li>
))}
or this :
<li>{this.state.events.activity}</li>

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