0
votes

I'm not sure what I've done wrong.... I'm making a simple app, using FourSquare app.

  1. User enters a location and venues are returned, via this.state.places.

I'm looping through the data to get all the venue info I need. Except for photos... I've had to write another axios request, to another FourSquare API, so I can get the photo of that venue ID...

Somehow, my ComponentDidMount functions, has hit my entire FourSquare quote limit. I'm on a free account - which is 95,000 calls a day?? I'm not sure what's wrong this this function, to cause that!

  componentDidMount() {
    axios.get('https://api.foursquare.com/v2/venues/explore?near=london&&client_id=MY_CLIENT_ID&client_secret=MY_CLIENT_SECRET&v=201806044&venuePhotos=1')
      .then((res) => {
        // RES VENUE DATA IS STORED IN PLACES
        this.setState(
          { places: res.data.response.groups[0].items.slice(0,12)});

        // LOOP THROUGH PLACES RES AND PULL OUT THE VENUE ID.
        for(var i = 0; i < this.state.places.length; i++) {
          const photosID = this.state.places[i].venue.id;
          console.log(this.state.places[i].venue.id);

          // NOW TAKE THE VENUE ID AND PLACE IT IN THIS SECOND API REQUEST
          return axios.get(`https://api.foursquare.com/v2/venues/${photosID}/photos?client_id=MY_CLIENT_ID&client_secret=MY_CLIENT_SECRET&v=20130815&ll=40.7,-74`);
        }
      })
      // THEN CONSOLE LOG THIS PHOTO RES DATA.
      .then((res) => {
        console.log('IDS RES:', res.data.response.photos.items[1]);
        // console.log('IDS RES:', res.data.response.photos.items[1].prefix.concat(res.data.response.photos.items[1].suffix));
      })
      .catch((err) => {
        console.log(err);
      });
  }

Basically, this is what I'm trying to do:

  1. Axios request from first API. Pass through state into another component and loop through venue data.
  2. Make second axios API request, which takes VenueID pulled out, from first API request and returns an image reference, (from second axios request)...

What's wrong with this code?

I'm also getting this error in console:

xhr.js:178 GET https://api.foursquare.com/v2/venues/4ac518cef964a5201aa620e3/photos?client_id=JUTTZIYT3Y2ECNHCORRDKIPLW1FNSAH2PW0XRLJCMIPRKY1Q&client_secret=220HPNZNEX3I34URWK4SK33IJBA4UJM3PFSRJIFCYRJTGBBN&v=20130815&ll=40.7,-74 429 ()
dispatchXhrRequest @ xhr.js:178
xhrAdapter @ xhr.js:12
dispatchRequest @ dispatchRequest.js:59
Promise.then (async)
request @ Axios.js:51
Axios.(anonymous function) @ Axios.js:61
wrap @ bind.js:9
(anonymous) @ index.js:41
Promise.then (async)
componentDidMount @ index.js:32
proxiedComponentDidMount @ createPrototypeProxy.js:66
(anonymous) @ ReactCompositeComponent.js:262
measureLifeCyclePerf @ ReactCompositeComponent.js:73
(anonymous) @ ReactCompositeComponent.js:261
notifyAll @ CallbackQueue.js:74
close @ ReactReconcileTransaction.js:78
closeAll @ Transaction.js:207
perform @ Transaction.js:154
batchedMountComponentIntoNode @ ReactMount.js:124
perform @ Transaction.js:141
batchedUpdates @ ReactDefaultBatchingStrategy.js:60
batchedUpdates @ ReactUpdates.js:95
_renderNewRootComponent @ ReactMount.js:317
_renderSubtreeIntoContainer @ ReactMount.js:399
render @ ReactMount.js:420
(anonymous) @ app.js:44
listener @ ready.js:23
index.js:49 Error: Request failed with status code 429
    at createError (createError.js:16)
    at settle (settle.js:18)
    at XMLHttpRequest.handleLoad (xhr.js:77)

FULL CODE

import React from 'react';
import axios from 'axios';

import Header from '../components/header';
import Navbar from '../components/Navbar';
import Results from '../components/Results';

import './index.css';

class Layout extends React.Component {

  constructor() {
    super();
    console.log('CONSTRUCTOR');

    this.state = {
      places: [],
      searchData: '',
      photos: [],
      city: 'London'
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // COMPONENT WILL MOUNT
  componentWillMount() {
    console.log('COMPONENT WILL MOUNT');
  }


  //
  componentDidMount() {
    axios.get('https://api.foursquare.com/v2/venues/explore?near=london&&client_id={MYCLIENTID}&client_secret={MYCLIENT_SECRET}&venuePhotos=1')
      .then((res) => {
        // RES VENUE DATA IS STORED IN PLACES
        this.setState(
          { places: res.data.response.groups[0].items.slice(0,12)});
        console.log(res.data.response.groups[0].items.slice(0,12));

        // LOOP THROUGH PLACES RES AND PULL OUT THE VENUE ID.
        for(var i = 0; i < this.state.places.length; i++) {
          const photosID = this.state.places[i].venue.id;
          console.log(this.state.places[i].venue.id);

          // NOW TAKE THE VENUE ID AND PLACE IT IN THIS SECOND API REQUEST
          return axios.get(`https://api.foursquare.com/v2/venues/${photosID}/photos?client_id={MYCLIENT}&client_secret={MYCLIENT}&ll=40.7,-74`);
        }
      })
      // THEN CONSOLE LOG THIS PHOTO RES DATA.
      .then((res) => {
        console.log('IDS RES:', res.data.response.photos.items[1]);
        // console.log('IDS RES:', res.data.response.photos.items[1].prefix.concat(res.data.response.photos.items[1].suffix));
      })
      .catch((err) => {
        console.log(err);
      });
  }

  // MAKE AXIOS REQUEST/COMPONENT DID MOUNT
  // componentDidMount() {
  //   console.log('COMPONENT DID MOUNT');
  //
  //   axios.get('https://api.foursquare.com/v2/venues/explore?near=london&&client_id={MYCLIENT}&client_secret={MYCLIENT}&venuePhotos=1')
  //     .then(res => {
  //       // console.log('DATA', res.data.response.groups[0].items);
  //       this.setState(
  //         { places: res.data.response.groups[0].items.slice(0,12)});
  //       this.setState(
  //         { photos: res.data.response.groups[0].items.slice(0,12)});
  //     });
  // }

  // MAKE AXIOS REQUEST/COMPONENT DID MOUNT
  // componentDidMount() {
  //   console.log('COMPONENT DID MOUNT');
  //
  //   axios.get('https://api.foursquare.com/v2/venues/explore?near=london&&client_id={MYCLIENT}&client_secret={MYCLIENT}&v=201806044&venuePhotos=1')
  //     .then(res => {
  //       // console.log('DATA', res.data.response.groups[0].items);
  //       this.setState(
  //         { places: res.data.response.groups[0].items.slice(0,12)});
  //       this.setState(
  //         { photos: res.data.response.groups[0].items.slice(0,12)});
  //     });
  // }

  // LISTEN TO FORM ENTRY/HANDLE CHANGE
  handleChange(e) {
    this.setState({ searchData: e.target.value }, () => console.log(this.state.searchData));
  }

  // CHANGE RESULTS AND APPLY SEARCH TERM TO AXIOS REQUEST
  handleSubmit(e){
    e.preventDefault();
    console.log(this.state.searchData);
    this.setState({ city: this.state.searchData });
    axios.get(`https://api.foursquare.com/v2/venues/explore?near=${this.state.searchData}&client_id={MYCLIENT}&client_secret={MYCLIENT}`)
      .then(res => {
        this.setState({ places: res.data.response.groups[0].items.slice(0,12)});
        // console.log(res.data.response.groups[0].items);
      });
  }


  render() {
    return(
      <div className="animated fadeIn">

        <Navbar />
        <Header
          handleChange={this.handleChange}
          handleSubmit={this.handleSubmit}
        />
        <Results
          places={this.state.places}
          photos={this.state.photos}
          city={this.state.city}
        />
      </div>
    );
  }
}


export default Layout;

export const query = graphql`
  query SiteTitleQuery {
    site {
      siteMetadata {
        title
      }
    }
  }
`;

ADDED JSX:

import React from 'react';
// import axios from 'axios';

const Results = () => {

  // for(var i = 0; i < photos.length; i++) {
  //   const photosID = photos[i].venue.id;
  //   console.log(photos[i].venue.id);
  //
  //   axios.get(`https://api.foursquare.com/v2/venues/${photosID}/photos?client_id={MYCLIENTID}&client_secret={MYCLIENTSECRET}&v=20130815&ll=40.7,-74`)
  //     .then(res => {
  //       console.log('IDS RES:', res.data.response.photos.items[1]);
  //       // console.log('IDS RES:', res.data.response.photos.items[1].prefix.concat(res.data.response.photos.items[1].suffix));
  //     });
  // }



  return (
    <section>
      <h3 className="title has-text-centered">Top 9 Recommendations for {city}</h3>
        <div className="columns is-multiline">
          {places.map((place, i) => <div className="column is-one-third" key={i}>
            <ul>
              <li>
                <div className="card-image box">
                  <figure className="">
                    <img className="image" src="https://s3-eu-west-1.amazonaws.com/video.gallereplay.com/artistarea/Restaurant%20at%20night_23376c1c-7d1e-4d6f-8efb-c581529540fb/Cinemagraph_plain/1280x720/cinemagraph.jpg"/>
                    <h4 className="has-text-left purple">{place.venue.name}</h4>
                    <h5 className="has-text-left has-text-grey">Category: {place.venue.categories[0].pluralName}</h5>
                    <h5 className="has-text-left has-text-grey">Why? {place.reasons.items[0].summary}</h5>
                    <h5 className="has-text-left has-text-link">Address: {place.venue.location.formattedAddress.slice(0,4)}</h5>
                    <h5 className="has-text-left has-text-link">ID: {place.venue.id}</h5>
                    {/* <img className="animated rotateIn" src={place.venue.categories[0].icon.prefix.concat(place.venue.categories[0].icon.suffix)}/> */}
                  </figure>
                </div>
              </li>
            </ul>
          </div>)}
        </div>

    </section>
  );
};

export default Results;
2
Please hide your client_id & secret from your code hereNick Prozee
I would recommend deleting this question and re-posting it as the ID is still visible in the edit history.Tyler
Please show the code that mounts/unmounts this component. I assume the problem is there and not in componentDidMountFuzzyTree
Hiya @FuzzyTree - I've added the full code. Thank you!Reena Verma
You didn't add the code that mounts LayoutFuzzyTree

2 Answers

1
votes

I read the docs and could not find anything strange in your code, however I see your URL is using different parameters then specified on the website: https://developer.foursquare.com/docs/api/venues/photos


PARAMETERS

Try changing:

https://api.foursquare.com/v2/venues/${photosID}/photos?client_id=MY_CLIENT_ID&client_secret=MY_CLIENT_SECRET&v=20130815&ll=40.7,-74`

to

https://api.foursquare.com/v2/venues/${photosID}/photos
1
votes

I think I found the problem, you are doing a return in your for loop. I modified the code a bit and removed the state logic but you should modify it to your own. Here is a example on how to handle promises in a for loop.
Note: I have not tested this so there could be some bugs.

Code

componentDidMount() {
   const exploreURL = 'https://api.foursquare.com/v2/venues/explore?near=london&&client_id=MY_CLIENT_ID&client_secret=MY_CLIENT_SECRET&v=201806044&venuePhotos=1';

   axios.get(exploreURL)
     .then(response => {
       //Store our fetch requests generated in the for loop
       var requests = [];
       // RES VENUE DATA IS STORED IN PLACES
       const places = response.data.response.groups[0].items.slice(0, 12);

       // LOOP THROUGH PLACES RES AND PULL OUT THE VENUE ID.
       for (var i = 0; i < places.length; i++) {
         const venueId = places[i].venue.id;
         console.log(venueId);

         // NOW TAKE THE VENUE ID AND PLACE IT IN THIS SECOND API REQUEST
         //Add request to all requests array
         requests.push(axios.get(`https://api.foursquare.com/v2/venues/${venueId}/photos`));
       }

        //This promise reolves when all requests have been resolved
        return Promise.all(requests);
     })
     // THEN CONSOLE LOG THIS PHOTO RES DATA.
     .then((res) => {
       console.log(res);
     })
     .catch((err) => {
       console.log(err);
     });
 }