Ravenous part 4 Error 'TypeError: Cannot read property 'map' of undefined'

Hi Everyone, i’ve been comparing my code to the solutions for part 4 and trawling topics on this forum to identify possible solutions but can’t find any- any help would be appreciated.

I’ve identified there is a problem with my fetch request- it’s not returning the raw data or the JSON stuff. I tripled checked my api key which is correct. no where in the instructions does it advise to use your ‘clientid’ so i havent. Can anyone advise what i’m missing? I feel i’ve checked every obvious error.

I’m getting the following message on my screen:

TypeError: Cannot read property 'map' of undefined
BusinessList.render

I know why i’m receiving it- my fetch isnt getting the information so the mapping is trying to iterate through an empty object of undefined. -.-

my code:

Yelp.js:

const Yelp = {
  search(term, location, sortBy) {
    return fetch(`https://cors-anywhere.herokuapp.com/https://api.yelp.com/v3/businesses/search?term=${term}&location=${location}&sort_by=${sortBy}`, {
      headers: {
        Authorization: `Bearer ${apiKey}`
      }
    }).then(response => {
      console.log(response)
      return response.json();
    }).then(jsonResponse => {
      console.log(jsonResponse)
      if (jsonResponse.businesses) {
        return jsonResponse.businesses.map(business => ({
          id: business.id,
          imageSrc: business.image_url,
          name: business.name,
          address: business.location.address1,
          city: business.location.city,
          state: business.location.state,
          zipCode: business.location.zip_code,
          category: business.categories[0].title,
          rating: business.rating,
          reviewCount: business.review_count
        }));
      }
    });
  }
};

export default Yelp;

BusinessList.js:

import React from 'react';
import './BusinessList.css';

import Business from '../Business/Business';

class BusinessList extends React.Component {
  render() {
    return (
      <div className="BusinessList">
        {
           this.props.businesses.map(business => {
            return <Business business={business} key={business.id} />
          })
        }
      </div>
    );
  }
}

export default BusinessList;

Business.js:

import React from 'react';
import './Business.css';
class Business extends React.Component {
  render() {
    return (
      <div className="Business">
      <div className="image-container">
        <img src={this.props.business.imageSrc} alt=''/>
      </div>
      <h2>{this.props.business.name}</h2>
      <div className="Business-information">
        <div className="Business-address">
          <p>{this.props.business.address}</p>
          <p>{this.props.business.state}</p>
          <p>{this.props.business.city}</p>
          <p>{this.props.business.zipCode}</p>
        </div>
        <div className="Business-reviews">
          <h3>{this.props.business.category.toUpperCase()}</h3>
          <h3 className="rating">{`${this.props.business.rating} stars`}</h3>
          <p>{`${this.props.business.reviewCount} reviews`}</p>
        </div>
      </div>
    </div>
    )
  }

}

export default Business


Searchbar.js:

import React from 'react';
import './SearchBar.css';
class SearchBar extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
     term: '',
     location: '',
     sortBy: 'best_match'
    }

    this.handleTermChange = this.handleTermChange.bind(this);
    this.handleLocationChange = this.handleLocationChange.bind(this);
    this.handleSearch = this.handleSearch.bind(this);
    this.handleSortByChange = this.handleSortByChange.bind(this);

    this.sortByOptions = {
      'Best Match': 'best_match',
      'Highest Rated': 'rating',
      'Most Reviewed': 'review_count'
    }
  }

  //getSortByClass() returns the current CSS class for a sorting option. 
  getSortByClass(sortByOption) {
  return this.state.sortBy === sortByOption ? 'active': '';
  }

  handleSortByChange(sortByOption) {
    this.setState({ sortBy: sortByOption});   
  }

  handleTermChange(e) {
    this.setState({term: e.target.value})
  }

  handleLocationChange(e) {
    this.setState({location: e.target.value})
  }

  handleSearch(e) {
    this.props.searchYelp(this.state.term, this.state.location, this.state.sortBy)
    e.preventDefault()
  }


  renderSortByOptions() {
    return Object.keys(this.sortByOptions).map(sortByOption => {
      let sortByOptionValue = this.sortByOptions[sortByOption];
    return <li 
    key={sortByOptionValue} 
    className={this.getSortByClass(sortByOptionValue)}
    onClick={this.handleSortByChange.bind(this, sortByOptionValue)}
    >{sortByOption}</li>
    });
    }

  render() {
    return (
     <div className="SearchBar">
     <div className="SearchBar-sort-options">
      <ul>
        {this.renderSortByOptions()}
      </ul>
    </div>
    <div className="SearchBar-fields">
      <input placeholder="Search Businesses" onChange={this.handleTermChange} />
      <input placeholder="Where?" onChange={this.handleLocationChange} />
    </div>
    <div className="SearchBar-submit">
      <a onClick={this.handleSearch}>Let's Go</a>
    </div>
  </div>
    )
  }
}

export default SearchBar;

Finally App.js:

import React from 'react';
import './App.css';

import BusinessList from '../BusinessList/BusinessList';
import SearchBar from '../SearchBar/SearchBar';
import Yelp from '../../util/Yelp';

class App extends React.Component {
  constructor(props) {
    super(props) 
      this.state = {
        businesses: []
      }
      this.searchYelp = this.searchYelp.bind(this) 
  }

  searchYelp(term, location, sortBy) {
    Yelp.search(term, location, sortBy).then(businesses => { 
      this.setState({businesses: businesses})
    })
  }

  render() {
  return (
    <div className="App">
    <h1>ravenous</h1>
    <SearchBar searchYelp={this.searchYelp}/>
    <BusinessList businesses={this.state.businesses} /> 
  </div>
    )
  }
}

export default App;

I’m seeing a lot of people get this error but i havent found a solution on my end. Any help would be appreciated. I feel i’m missing something very obvious.

Thanks in advance!

Hello,

Since you mentioned that you checked your api key to confirm it’s correct, I’m assuming you usually have a const apiKey = 'long_api_key_here'; at the top of your Yelp.js file, but you didn’t post it to keep it secret.

If that is accurate, then you actually aren’t missing anything that was included in the steps for the project. I dropped all of your files into my project (and added my apiKey) and was able to get back results:

I’ve found that Yelp’s APIs can be picky with location names, so I often use something I’m 100% sure will work for testing. For the screenshot above, I used the term: Pizza and the location: New York

Another thing that I’ve found is that the project steps don’t account for something going wrong, like Yelp not liking a search request. You could account for this in a number of ways, such as checking the value of businesses before calling this.setState with it. It’s not included in the steps though, so you didn’t miss it.

Congratulations on finishing the Ravenous project!

2 Likes

Hi Selectall,

Thanks so much for going out of your way to check my code- it was driving me nuts not being able to discern if there was indeed a bug. The problem is definitely with my key then!

I’ll have to see if i can somehow generate another key or try it your way and input pizza from new yor to see if it at least generates a valid response form the api.

You’re right, i think if the response is empty, then i’d want to render a placeholder of some sort- it doesnt explain the error message i get in my console which is what through me.

Thanks, i’ve moved onto Jamming for now but will come back to this project and iron it out before deploying hehe

1 Like

Hi Selectall,

I am having the same issue as sc6636956187 (our code is the same) but the difference is when I log the jsonResponse from Yelp.js to the console I see all the business objects but in App.js the business object from the .then() logs in the console logs as undefined, is this also an API key issue?

Hello @jbarlati, welcome to the forums.

Since you’re seeing all the business objects when you log the jsonResponse in Yelp.js, it doesn’t sound like an API key issue. It sounds like there could be a problem in what you’re doing with the jsonResponse after that, perhaps in your map() call or with how it’s being returned. If you show me your code, I can help with a second set of eyes on it.

Thanks @selectall,

I was thinking the same thing but wasn’t sure. Here is my code

Yelp.js

const Yelp = {

  search(term, location, sortBy) {

    return fetch(

      `https://cors-anywhere.herokuapp.com/https://api.yelp.com/v3/businesses/search?term=${term}&location=${location}&sort_by=${sortBy}`,

      { headers: { Authorization: `Bearer ${apiKey}` } }

    )

      .then((response) => {

        return response.json();

      })

      .then((jsonResponse) => {

        if (jsonResponse.businesses) {

          jsonResponse.businesses.map((business) => {

            console.log(business.name);

            return {

              id: business.id,

              imageSrc: business.image_url,

              name: business.name,

              address: business.location.address1,

              city: business.location.city,

              state: business.location.state,

              zipCode: business.location.zip_code,

              category: business.categories[0].title,

              rating: business.rating,

              reviewCount: business.review_count,

            };

          });

        }

      });

  },

};

export default Yelp;

App.js

import React from 'react';

import './App.css';

import BusinessList from '../BusinessList/BusinessList';

import SearchBar from '../SearchBar/SearchBar';

import Yelp from '../../util/yelp';

class App extends React.Component {

  constructor(props) {

    super(props);

    this.state = { businesses: [] };

    this.searchYelp = this.searchYelp.bind(this);

  }

  searchYelp(term, location, sortBy) {

    Yelp.search(term, location, sortBy).then((businesses) => {

      this.setState({ businesses: businesses });

    });

  }

  render() {

    return (

      <div className="App">

        <h1>ravenous</h1>

        <SearchBar searchYelp={this.searchYelp} />

        <BusinessList businesses={this.state.businesses} />

      </div>

    );

  }

}

export default App;

BusinessList.js

import React from 'react';

import './BusinessList.css';

import Business from '../Business/Business';

class BusinessList extends React.Component {

  render() {

    return (

      <div className="BusinessList">

        {this.props.businesses.map((business) => {

          console.log(business);

          return <Business business={business} />;

        })}

      </div>

    );

  }

}

export default BusinessList;

@jbarlati

You’re returning the object in your callback for the map(), but you’re not actually returning what map() returns so App.js only gets undefined.

return jsonResponse.businesses.map((business) => {

and you should be good to go

Oh wow, totally missed that somehow. Thanks @selectall !

1 Like