Gudarzi
Gudarzi

Reputation: 575

Need help on parsing JSON data from this API in a React app

I'm trying to get Bitcoin Price from Coindesk API. This is my app:

import React from 'react';
import ReactDOM from 'react-dom';

let bpiURL = 'http://api.coindesk.com/v1/bpi/currentprice.json';

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: {}
        };
    }

    componentDidMount() {
        fetch(bpiURL)
            .then(response => response.json())
            .then(res => {
                console.log(res);
                return res;
            })
            .then(response => this.setState({ data: response }));
    }

    render() {
        return (
            <div>
                <p>
                    {this.state.data.disclaimer}
                </p>
            </div>
        );
    }
}

ReactDOM.render(<App />, document.getElementById('root'));
    
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

The problem is that it works with this.state.data.disclaimer and this.state.data.chartName but it doesn't work with this.state.data.bpi.USD.rate which is what I need. How can I get that value?

EDIT: this is what I get from this.state.data :

Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead. in p (at index.js:42) in div (at index.js:37) in App (at index.js:49)

Upvotes: 1

Views: 254

Answers (2)

PGN 508
PGN 508

Reputation: 11

import React, {Component} from 'react';


const bpiURL = "https://api.coindesk.com/v1/bpi/currentprice.json";

class App extends Component {
    // you should check component life cycle to prevent updating from fetch when component is unmounted
    _isMounted = false;
    state = {
        data: null,
        error: null

    };

    componentDidMount() {

        this._isMounted = true;
        fetch(bpiURL)
            .then(response => response.json())

            .then(response => this._isMounted && this.setState({data: response}))
            // introduce an error catch
            .catch(error => this._isMounted && this.setState({error}))
    }

    componentWillUnmount() {
        this._isMounted = false;
    }


    render() {
        const {data, error} = this.state;
        return (
            <div className="App">
                {/* optional : you could show the error message */}
                <p> {`USD rate :  ${ (data && data.bpi.USD.rate) || error }`}</p>
            </div>
        );
    }
}

export default App;

Upvotes: 0

Tholle
Tholle

Reputation: 112777

this.state.data.bpi.USD.rate works, but only once the request has completed. Before that this.state.data.bpi will give undefined, and trying to access USD on that will give rise to an error.

You could change your default data to null, and check if data is set before you use it in the render method.

Example

let bpiURL = "https://api.coindesk.com/v1/bpi/currentprice.json";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: null
    };
  }

  componentDidMount() {
    fetch(bpiURL)
      .then(response => response.json())
      .then(response => this.setState({ data: response }));
  }

  render() {
    return (
      <div>
        <p>{this.state.data && this.state.data.bpi.USD.rate}</p>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Upvotes: 2

Related Questions