JSON Data Object Handling in React - reactjs

Cant figure it out how to extract data from parsed and stored json object from state ... i have tried many ways but getting errors (data from openweathermap)
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
data: null
};
}
getWeather(url) {
fetch(url)
.then(res => res.json())
.then(data =>
this.setState({
isLoading: false,
data: data
})
)
.catch(error => console.log("Error Loading data " + error));
}
componentDidMount() {
navigator.geolocation.getCurrentPosition(position => {
const url = `${API}lat=${position.coords.latitude}&lon=${position.coords.longitude}&${APPID}`;
this.getWeather(url);
});
}
render() {
return (
<div>
{console.log(this.state.data)}
{/*renders json*/}
<h1>{this.state.data.name}</h1>
</div>
);
}
}

I believe you might be getting cannot read property 'name' of null. Not sure about the exact error but something like that.
Try to use
<h1>{ this.state.data && this.state.data.name }</h1>
Till the time API is not giving the response, your data in the state is null so you cannot access data.name.

Related

React - get data with axios

In my react app that is based on class components, My response API got from open weather fixes after several lags.
this is my state
class Weather extends Component {
constructor(props) {
super(props);
this.state = {
weatherData: undefined,
weatherDescription: undefined,
};
}
My thinking was that when my componentDidMount,
weather API getting from openWeather and set it in state
componentDidMount() {
axios
.get(
`http://api.openweathermap.org/data/2.5/weather?id=someCityId&units=metric&appid=myApiKey`
)
.then((response) => {
if (response.request.status === 200) {
this.setState({
weatherData: response.data.main.temp,
weatherDescription: response.data.weather[0].description,
weatherTextDisplay: this.state.airConditionsText.filter((item)=>{
return item["id"] === response.data.weather[0].id
})
});
}else{throw Error('No internet')}
})
.catch(error => Error.message)
and I want to update data when the city is changing, in componentDidUpdate the data get again from the openWeather
componentDidUpdate() {
axios
.get(
`http://api.openweathermap.org/data/2.5/weather?id=someCityId&units=metric&appid=myApiKey`
)
.then((response) => {
if (response.request.status === 200) {
this.setState({
weatherData: response.data.main.temp,
weatherDescription: response.data.weather[0].description,
weatherTextDisplay: this.state.airConditionsText.filter((item)=>{
return item["id"] === response.data.weather[0].id
})
});
}else{throw Error('No internet')}
})
.catch(error => Error.message)
}
But the problem is that when my response receives, it faces a lag that causes data jumps several times to previous data and new data until it fixes
I do not completely understand the question, but this 'lags' because the action of fetching something from an external source is async and needs time to complete.
As for the second 'part' of displaying the loading text you have to set a variable (preferably in state which indicates the loading state of this component)
eg.
constructor(props) {
super(props);
this.state = {
loading: false,
airConditionsText: null,
// Other stuff you have in state
};
}
componentDidUpdate() {
this.setState({loading: true}) // Start of loading
axios
.get(
`http://api.openweathermap.org/data/2.5/weather?id=${this.state.inputId}&units=metric&appid=myApiKey`
)
.then((response) => {
if (response.request.status === 200) {
this.setState({
weatherData: response.data.main.temp,
weatherDescription: response.data.weather[0].description,
weatherTextDisplay: this.state.airConditionsText.filter((item)=>{
return item["id"] === response.data.weather[0].id
})
});
}else{throw Error('No internet')}
})
.catch(error => Error.message)
.finally(() => this.setState({loading: false})) // End of loading
.finally is being trigger once the async operation (fetching the data from weatherAPI) finishes with either error or success which is the time to stop loading.
Then you can use this.state.loading in component render to show loading text
eg.
render() {
return (
<div>
{this.state.loading
? <div> Loading... </div>
: <div>{this.state.airConditionsText}</div> // other stuff you want to display
}
</div>
);
}

React problems when i try to make an api call using fetch

i have a problem i try to make an api call to https://randomuser.me/api/ using fetch and i try to setstate my value array to the api data and then to map and i cant figure out where is the problem in my code because i get some errors
import "./App.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: [],
};
}
componentDidMount() {
fetch("https://randomuser.me/api/")
.then((res) => res.json())
.then((data) => this.setState({ value: data }));
}
render() {
return (
<div>
<p>test</p>
<div className="map">
{this.state.value.map((item) => (
<p>{item.gender}</p>
))}
</div>
</div>
);
}
}
export default App;
The endpoint you are fetching from sends the response as an object, when you try to setState with the call this.setState({ value: data }) it sets the entire response object as this.state.value. That is why you get the error "this.state.value.map is not a function" because this.state.value was replaced as an object by the setState call.
I believe you want the value of results property from the response object which has the correct array data for the user. You can simply change the setState call to set the value as data.results.
componentDidMount() {
fetch("https://randomuser.me/api/")
.then((res) => res.json())
.then((data) => this.setState({ value: data.results }));
}

Fetch some data from an api with React

Im trying to fetch some data from an api but for some reason it's not working, i also tried with Object.key.
I have been doing api fetch a couple of times but i guess i don't understand this JSON format
Here is my code:
class CryptoNews extends Component {
constructor(props){
super(props);
this.state = {
news: []
}
}
componentDidMount(){
fetch('https://min-api.cryptocompare.com/data/v2/news/?feeds=cryptocompare,cointelegraph,coindesk&extraParams=YourSite')
.then(res => res.json())
.then(data => this.setState({
news: data
})
)}
render() {
return (
<div>
{this.state.news.map((key) => (
<div key={key.id}>
<h2>{key.body}</h2>
</div>
))}
</div>
)
}
}
You need to take the Data property from the response object.
So:
news: data.Data
You are trying to get the Data array and set it to this.state.news.
The format of JSON message is like this.
{
"Type":100,
"Message":"News list successfully returned",
"Promoted":[],
"Data":[],
"RateLimit":{},
"HasWarning":false
}
your componentDidMount method should be like following
componentDidMount(){
fetch('https://min-api.cryptocompare.com/data/v2/news/?
feeds=cryptocompare,cointelegraph,coindesk&extraParams=YourSite')
.then(res => res.json())
.then(data => this.setState({
news: data.Data
})
)}

React Display Data from API Fetch & Map

i'm attempting to learn React by making a movie web app. Im trying to pull upcoming movies from a movie api, and display information from it, however i keep getting an error:
Line 37: Expected an assignment or function call and instead saw an
expression no-unused-expressions
Please excuse me as im not too familiar with this framework and im not a JS pro. Heres my code:
export default class Upcoming extends Component {
state = {
upcomingMovies: []
}
fetchUpcoming() {
fetch(`https://api.themoviedb.org/3/movie/upcoming?api_key=${API_KEY}&language=en-US&page=1`)
// We get the API response and receive data in JSON format...
.then(response => response.json())
// ...then we update upcomingMovies State
.then(data =>
this.setState({
upcomingMovies: data.results
})
)
}
componentDidMount(){
this.fetchUpcoming();
}
render() {
return(
<Container>
{ this.state.upcomingMovies.map((upcomingMovie) => {
console.log(upcomingMovie);
const title = upcomingMovie.title;
console.log(title);
<h1>{title}</h1>
})}
</Container>
)
}
}
Map function should return something to generate ui.
export default class Upcoming extends Component {
state = {
upcomingMovies: []
}
fetchUpcoming() {
fetch(`https://api.themoviedb.org/3/movie/upcoming?api_key=${API_KEY}&language=en-US&page=1`)
// We get the API response and receive data in JSON format...
.then(response => response.json())
// ...then we update upcomingMovies State
.then(data =>
this.setState({
upcomingMovies: data.results
})
)
}
componentDidMount(){
this.fetchUpcoming();
}
render() {
return(
<Container>
{ this.state.upcomingMovies.map((upcomingMovie) => (
<h1>{upcomingMovie.title}</h1>
))}
</Container>
)
}
}
You're missing a return statement in the last line of your map function. It should be return <h1>{title}</h1>
You should write fetchUpcoming by using arrow function. So, you can use this.setState() method on scope of fetchUpcoming function. EX:
const fetchUpcoming = async() {
try {
let response = await fetch(
`https://api.themoviedb.org/3/movie/upcoming?api_key=${API_KEY}&language=en-US&page=1`,
);
let responseJson = await response.json();
return this.setState({
upcomingMovies: responseJson.data.results
})
} catch (error) {
console.error(error);
}
}

React Multiple Fetch from state

so I am trying to fetch my SWAPI json-server twice using the homeworld id to get the homeworld name but I just get "TypeError: Cannot read property 'name' of undefined". Im fairly new to React so if it looks messy im sorry! Thanks in advance!
import React, { Component } from 'react';
import './Card.css';
const person = personID =>
`http://localhost:3008/people/${personID}`
const picture = pictureID =>
`http://localhost:3008/${pictureID}`
// const planet = planetID =>
// `http://localhost:3008/planets/${planetID}`
class Card extends Component {
constructor(props){
super(props);
this.state ={
requestFailed: false,
person: 1,
planet: 4
}
}
componentDidMount(){
fetch(person(this.state.person))
.then(response => {
if(!response.ok) {
throw Error("Network Request Failed");
}
return response
})
.then(d => d.json())
.then(d => {
this.setState({
cardData: d
})
}, () => {
this.setState({
requestFailed: true
})
})
fetch(`http://localhost:3008/planets/${this.state.cardData.homeworld}`)
.then(data => data.json())
.then(data => {
this.setState({
homeData: data
})
})
}
render() {
if(this.state.requestFailed === true) return <p>Error please try
again!</p>
if(!this.state.cardData) return <p>Loading ...</p>
return (
<div className='card'>
<div className='card-content'>
<div className='card-name'>{this.state.cardData.name}</div>
<img src={picture(this.state.cardData.image)}
alt='profile'/>
<p>
<span>Birthday:</span>
<span>{this.state.cardData.birth_year}</span>
</p>
<p>
{/* Note that in order to get the homeworld's name, you have to get the planet name from a different endpoint than the people */}
<span>Homeworld:</span>
<span>{this.state.homeData.name}</span>
</p>
</div>
</div>
);
}
}
export default Card;
It looks like the first problem is that you're attempting to render homeData.name before it's loaded. You should probably have a loading check similar to the cardData loading check. Or you could just render nothing until it's loaded:
{this.state.homeData ?
<span>{this.state.homeData.name}</span> :
<span>Loading...</span>
}
The 2nd problem is that you're doing the second fetch of homeData at the same time as the first fetch. So this line:
fetch(`http://localhost:3008/planets/${this.state.cardData.homeworld}`)
Will always fail because the cardData is not loaded into the state yet when it runs.
What you should do is move it inside the response part of the first request:
fetch(person(this.state.person))
.then(response => {
if(!response.ok) {
throw Error("Network Request Failed");
}
return response
})
.then(d => d.json())
.then(d => {
this.setState({
cardData: d
})
fetch(`http://localhost:3008/planets/${d.homeworld}`)
.then(data => data.json())
.then(data => {
this.setState({
homeData: data
})
})
}, () => {
this.setState({
requestFailed: true
})
})
It would help to extract these into separate functions to clean it up a bit.

Resources