简体   繁体   中英

Passing a prop from a Parent component becomes null in the Child component React

I am making a simple React site which fetches some data from an API ( this API ) and then display it on the page. The endpoint I am using is the skyblock/auctions endpoint. What this returns is a list of objects, which I want to get the first one of and then pass it to a child component. The parent can successfully get the data, however when I pass it to the child and console.log it, it returns null . The only reason I can think of for why its doing this is because the parent component hasn't finished fetching the data yet, but I am not sure how to make it render only after its finished.

Here is the code for the parent component AuctionViewer :

class AuctionViewer extends Component {
  state = { data: null}

  loadData = async () => {
    let url = "https://api.hypixel.net/skyblock/auctions?key=INSERT_KET_HERE" 
    let response = await fetch(url);
    let json = await response.json();

    this.setState({data: json.auctions[0]}, function () {
      console.log(this.state.data)
    });
  }

  componentDidMount() {
    this.loadData();
    setInterval(this.loadData, 60 * 1000);
  }

  render() { 
    return (<Auction data={this.state.data} />);
  }
}

And here is the child component Auction :

class Auction extends Component {
  state = {
    loading: true,

    item: null,
    price: null,
    startPrice: null,
    time: null,
  };

  loadData() {
    let data = this.props.data;
    console.log(data);

    let end = new Date(data.end - Date.now());
    let timeLeft = end.getHours() + ":" + end.getMinutes() + ":" + end.getSeconds();     
    this.setState({loading: false, item: data.item_name, price: data.highest_bid_amount, startPrice: data.starting_bid, time: timeLeft, timestamp: end});
  };

  componentDidMount() {
    this.loadData();
  }

  render() {
    return (
      <div className="gridBox">
        {this.state.loading ? (
          <p>Loading...</p>
        ) : (
          <div>
            <p>Item: {this.state.item}</p>
            <p>Top Bid: {this.state.price}</p>
            <p>Start Bid: {this.state.startPrice}</p>
            <p>Time Left: {this.state.time}</p>
          </div>
        )}
        <button onClick={this.loadData}>Refresh</button>
      </div>
    );
  }
}

The only reason I can think of for why its doing this is because the parent component hasn't finished fetching the data yet...

That's right.

...but I am not sure how to make it render only after its finished.

You have two options:

  1. (I don't think you want this one.) Move the ajax call into the parent of the parent component, and only render the parent component when you have the data.

  2. Have the parent component render a "loading" state of some kind until the data is available

#2 looks something like this:

render() { 
  const { data } = this.state;
  return (data ? <Auction data={data} /> : <em>Loading...</em>);
}

...but probably with something more attractive than just a <em>Loading...</em> . :-)

The simplest was is with some conditional rendering while AuctionViewer is "fetching" the data. The initial state is null and this is passed to Auction , but you can conditionally render other UI or null while waiting.

render() { 
  const { data } = this.state;
  return data ? (
    <Auction data={data} />
  ) : <div>Loading...</div>;
}

Or return null to indicate to react that nothing should be rendered.

render() { 
  const { data } = this.state;
  return data ? (
    <Auction data={data} />
  ) : null;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM