Reputation: 141
I am building a simple cryptocurrency app with coinmarketcap api. my get request is inside of componentDidMount. When I console.log the received object inside of the async function and inside the render - it works. But When I actually trying to display the received data inside of return (h3 element), the received object becomes undefined. I get a typeError "cannot read property urls of undefined". What am I doing wrong here?
import React, { Component } from "react";
import axios from "axios";
import { Row, Col, Badge } from "react-bootstrap";
class Crypto extends Component {
constructor(props) {
super(props);
this.state = {
singleCrypto: {},
id: this.props.match.params.id
};
}
componentDidMount() {
this.getEachCrypto();
}
async getEachCrypto() {
try {
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const id = this.props.match.params.id;
let data = await axios.get(
proxyurl +
"https://pro-api.coinmarketcap.com/v1/cryptocurrency/info?id=" +
id,
{
headers: {
"X-CMC_PRO_API_KEY": "e1eb1f30-5c4e-43aa-be04-4b50df00807a"
}
}
);
this.setState({ singleCrypto: data.data.data });
} catch (error) {
console.log("request failed", error);
}
console.log(
this.state.singleCrypto[this.props.match.params.id].urls.website[0]
); // this works
}
render() {
const { singleCrypto } = this.state;
if (Object.keys(singleCrypto).length === 0) {
console.log("Loading");
} else {
console.log(singleCrypto[this.props.match.params.id].urls.website[0]); // this works
}
return (
<div>
<div className="crypto fluid">
<Row>
<Col lg md={3}>
<h3>
{singleCrypto[this.props.match.params.id].urls.website[0]} // fails!!!
</h3>
<div>
<ul>
<li>Rank</li>
<li>Website</li>
<li>Explorer</li>
<li>Message Board</li>
<li>Source Code</li>
<li>Tech Docs</li>
<li>Tags</li>
</ul>
</div>
</Col>
<Col lg md={7}>
<h3>Price, % change</h3>
<Badge variant="primary">Buy</Badge>
<Badge variant="primary">Exchange</Badge>
<Badge variant="primary">Gamble</Badge>
<Badge variant="primary">Earn Crypto</Badge>
</Col>
<Col lg md={2}>
2 parts
</Col>
</Row>
</div>
</div>
);
}
}
export default Crypto;
here is my data sample:
"data": {
"1": {
"urls": {
"website": [
"https://bitcoin.org/"
],
"technical_doc": [
"https://bitcoin.org/bitcoin.pdf"
],
"twitter": [],
"reddit": [
"https://reddit.com/r/bitcoin"
],
"message_board": [
"https://bitcointalk.org"
],
Upvotes: 0
Views: 353
Reputation: 281646
You must return null
or a loading state
when the data isn't available
if (Object.keys(singleCrypto).length === 0) {
return null; // you can maintain a loading state too untill data is available
}
With Loading state
class Crypto extends Component {
constructor(props) {
super(props);
this.state = {
singleCrypto: {},
id: this.props.match.params.id.
isLoading: true,
};
}
componentDidMount() {
this.getEachCrypto();
}
async getEachCrypto() {
try {
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const id = this.props.match.params.id;
this.setState({isLoading: true});
let data = await axios.get(
proxyurl +
"https://pro-api.coinmarketcap.com/v1/cryptocurrency/info?id=" +
id,
{
headers: {
"X-CMC_PRO_API_KEY": "e1eb1f30-5c4e-43aa-be04-4b50df00807a"
}
}
);
this.setState({ singleCrypto: data.data.data, isLoading: false });
} catch (error) {
console.log("request failed", error);
this.setState({ isLoading: false });
}
}
render() {
const { singleCrypto } = this.state;
if(this.state.isLoading) {
return <div>Loading...<div>
}
...
}
}
export default Crypto;
Upvotes: 1