ShocKwav3_
ShocKwav3_

Reputation: 1760

How to get promise value to react component?

I am trying get data from an api endpoint and display it on a react component.

When I am formulating components depending on the data from state.trainData by mapping, I also require to get data from another api endpoint for each of the elements of state.trainData.

I am using a helper function to fetch me data but thats where i hit a roadblock. I do get the data fine but the problem is I can not get it out on a variable or so to place it in a component.

In the render function after the call of getSpecificTrainDetails, I got the data on response.data. I have been trying for two hours to figure out how to take the data and place it in the desired component but I reached nowhere! Help would be very much appreciated.

componentDidMount = () => {
    axios.get('https://rata.digitraffic.fi/api/v1/live-trains?station=SLO')
      .then((response) => {
        //console.log(response.data);
        this.setState({
          trainData: response.data,
        });
      }).catch((error) => {
        console.log(error);
      });
  }

    getSpecificTrainDetails = (trainNum, date) => {
            let apiLink = "https://rata.digitraffic.fi/api/v1/compositions/";
            let apiConstructedLink = apiLink + trainNum + "?departure_date=" + date;
            return axios.get(apiConstructedLink)
            .then((response) => {
              return response;
            }).catch((error) => {
              console.log(error);
            });
          }    

    render(){   
        let content = this.state.trainData.map((item, i) => {
            this.getSpecificTrainDetails(item.trainNumber, item.departureDate).then((response) => {
                            console.log(response.data);
                          });

                          return <Popup key={i}
                                <Card> //VALUE FROM 1ST API GOES HERE!!! </Card>
                                 // VALUE FROM 2ND API GOES HERE!!
                                </Popup>;
                        });
    }

For example from the 1st api i get the trains number and date and with this date and number passed along to the 2nd api i get the trains details.

Upvotes: 2

Views: 7358

Answers (1)

mdziekon
mdziekon

Reputation: 3627

You should never, ever call anything asynchronous in the render function.

What you should do instead is to call the getSpecificTrainDetails inside of the componentDidMount method:

componentDidMount = () => {
    axios.get('https://rata.digitraffic.fi/api/v1/live-trains?station=SLO')
    .then((response) => {
        const trainData = response.data;

        // For each train data, fetch it's specific details
        const promises = trainData.map((item, i) => {
            return this.getSpecificTrainDetails(
                item.trainNumber,
                item.departureDate
            ).then((trainResponse) => {
                // Create a new object with both
                // item's regular data and it's specific data
                return {
                    idx: i,
                    item,
                    specificDetails: trainResponse.data
                };
            });
        });

        // Await on all promises
        return Promise.all(promises);
    }).then((trainsData) => {
        // When all results have arrived, put them into the component's state
        this.setState({
            trainData: trainsData
        });
    }).catch((error) => {
        console.log(error);
    });
}

getSpecificTrainDetails = (trainNum, date) => {
    let apiLink = "https://rata.digitraffic.fi/api/v1/compositions/";
    let apiConstructedLink = apiLink + trainNum + "?departure_date=" + date;

    return axios.get(apiConstructedLink)
        .then((response) => {
            return response;
        }).catch((error) => {
            console.log(error);
        });
}

render() {
    if (!this.state.trainData) {
        return;
    }

    // This will render once all the specific results have been fetched
    return this.state.trainData.map((item, i) => {
        return (
            <Popup key={i}>
                <Card>
                    1st API call data:
                    { item.item.something }
                </Card>
                2nd API call data:
                { item.specificDetails.something }
            </Popup>
        );
    });
}

Upvotes: 2

Related Questions