Reputation: 313
I would like to display some fetched information stocked into a state with react.
constructor(props) {
super(props);
this.state = { price: [] };
}
fetchResult = () => {
fetch('https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC,ETH&tsyms=USD,EUR', {
})
.then(response => {
return response.json();
})
.then(price => {
this.setState({ price: price })
console.log("TCL: price", price);
console.log("TCL: this.state.price.BTC.USD", this.state.price.BTC.USD)
})
.catch(error => {
console.error(error);
});
}
componentDidMount = () => {
this.fetchResult()
setInterval(this.fetchResult, 30000000)
}
render() {
return (
<div className="overviewcard">
<p>{this.state.price}</p>
<p>{this.state.price.BTC.USD}</p>
</div>
);
}
// Console.log(price) = {"BTC":{"USD":10208.24,"EUR":9228.96},"ETH":{"USD":213.4,"EUR":192.97}}
// Console.log(this.state.price.BTC.USD) = 10208.24
So when I'm trying to display it with :
{this.state.price.BTC.USD}
I get this error:
"TypeError: Cannot read property 'USD' of undefined"
{this.state.price}
I get this error:
"Objects are not valid as a React child"
I read other topics and i did not find any solutions, i tried to bind "this" and put function arrow. I don't know what to do about it.
Thanks for your help
Upvotes: 0
Views: 418
Reputation: 10873
A few issues with your code:
You set price
as an empty array on initial state, but then try to access it as object. Change your initial state to this.state = { price: {} };
setState
is async, so logging it to console straight after setting will show the old value, you need to use the callback to setState
:
this.setState({ price: price } , () => {
console.log("state:", this.state);
})
You're trying to render this.state.price
, but it's supposed to be an object, so that's why you get an error.
Do not use setInterval
in componentDidMount
as it will repeatedly call your api fetch method with the same url.
You're trying to render this.state.price.BTC.USD
, however before the data has been fetched and set to the state, the price value on state doesn't have any props, and you'll get cannot access property 'BTC' of undefined
error. In this case a better idea is to delay the render until the data is fetched. You can do it by showing a loader meanwhile. Additionally, it's a good idea to have some error handling, where you'd display an error message if the data fetching wasn't successful:
constructor(props) {
super(props);
this.state = {
price: {},
error: false, // Track error state
loading: true // set loading to true in the beginning
};
}
fetchResult = () => {
this.setState({ error: false });
fetch(
"https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC,ETH&tsyms=USD,EUR",
{}
)
.then(response => {
return response.json();
})
.then(price => {
this.setState(
{
price: price,
loading: false // Disable loading after data is fetched
},
() => {
console.log("state:", this.state);
}
);
})
.catch(error => {
console.error(error);
this.setState({ error: true, loading: false }); // Also disable loading in case of error
});
};
componentDidMount = () => {
this.fetchResult();
};
render() {
if (this.state.error) {
return <p>Error message here</p>;
}
return this.state.loading ? (
<p>Loading...</p> // Show loader before the data is ready
) : (
<div className="overviewcard">
<p>{this.state.price.BTC.USD}</p>
</div>
);
}
I have recently wrote a post about the most common mistakes with React, which you may find useful.
Also here's a working sandbox.
Upvotes: 2