Stave
Stave

Reputation: 313

Accessing to a state after a fetch to displayed it

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

Answers (1)

Clarity
Clarity

Reputation: 10873

A few issues with your code:

  1. 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: {} };

  2. 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);
})

  1. You're trying to render this.state.price, but it's supposed to be an object, so that's why you get an error.

  2. Do not use setInterval in componentDidMount as it will repeatedly call your api fetch method with the same url.

  3. 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

Related Questions