Ravenous part 4 same old <Cannot read property 'map' of undefined> error

Hi there,

I’ve spent some amount of time checking all the answers given to the same topic but I couldn’t find the answer to my issue…Can anyone please help me?
Below is my code.

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;

Yelp.js

const apiKey =
  "FivVW4IH7FCjk7CnynCAYHu1oeharjNhtyp9gkXJ4iVbTE1E-c213Yzs11xj_fh12oUuoUYdk32klsyC5y5NQ-8eG1U1FoWc566YuAnlf3twpAmspCsePOW6HNmOX3Yx"; // Insert API key here.

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) {
          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;

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;

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.city}</p>
            <p>{`${this.props.business.state} ${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;

and 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(sortByOption) {
    if (this.state.sortBy === sortByOption) {
      return "active";
    }
    return "";
  }

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

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

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

  handleSearch(event) {
    this.props.searchYelp(
      this.state.term,
      this.state.location,
      this.state.sortBy
    );

    event.preventDefault();
  }

  renderSortByOptions() {
    return Object.keys(this.sortByOptions).map((sortByOption) => {
      let sortByOptionValue = this.sortByOptions[sortByOption];
      return (
        <li
          className={this.getSortByClass(sortByOptionValue)}
          key={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;

I have used even the code provided in the solution given by Codecademy but it gives me the same Typerror.

Thank you!!!
Adrian

Hello, your code is actually working correctly. It’s just that there isn’t great error handling when Yelp returns back an error or no results.

I dropped your code for each of the files you provided into my project and was able to get results for a simple search like Pizza in New York:

If you click “Let’s Go” without any search parameters, or if you use a term and/or location it doesn’t understand, then it will result in the TypeError that you posted.

It isn’t part of the project steps that they provide, but you can handle this in different ways. Ultimately, you’d probably want to make sure the state of businesses in App.js never gets set to undefined. You could handle this in Yelp.js by returning an empty array if there are no listings found or checking the value before setting the state in the searchYelp() function in App.js.

You handling that would be considered an optional “bonus” since it isn’t covered in the steps for the project.

Congratulations on completing your Ravenous project!

1 Like

Thank you very much for your quick answer. It really helped.

One option to getting rid of the problem when business array is undefined would be to do conditional rendering using the && operator in the JSX. This line of code makes sure that .map method only runs when businesses is defined.

        { this.props.businesses &&
            this.props.businesses.map((business) => {
              return <Business business={business} key={business.id} />;
        })}

The tertiary operator could also be used to show an alternative message in case businesses is undefined.

Thank you for your input. Adrian

1 Like


it works! …but somehow it messed the styling…any idea why ?

Nice! Congrats on getting it to work.

It looks like a line-height got messed up along the way. If you haven’t touched the CSS and it’s only looking like this for you now, then you may have a typo in a className in the JSX somewhere.

The screenshot I posted included all of your JS files but none of your CSS files, so we know that with those versions you posted, the spacing should be correct if the CSS files are the ones the project started with. You could go back and compare the changes you made since then to be absolutely sure there are no typos. If you modified the CSS yourself, then that would obviously be something you’d have to dive into and compare with the original CSS files they gave us.

I haven’t touched the code. From what I see, the component responsible for styling that data is am I right ? I looked but cannot figure out where is the glitch… Can you see it ?

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.city}</p>
            <p>{`${this.props.business.state} ${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;

Business.css

.Business {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    width: 16.66rem;
    margin: 0 .5rem 2.3rem .5rem;
  }
  
  .Business .image-container {
    height: 16.66rem;
    margin-bottom: 1rem;
  }
  
  .Business h2 {
    margin-bottom: .5rem;
    font-size: 1.2rem;
    font-weight: 600;
  }
  
  .Business-information {
    display: flex;
    justify-content: space-between;
  }
  
  .Business-information p {
    font-size: .88rem;
    font-weight: 300;
    line-height: 1rem;
  }
  
  .Business-address {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
  }
  
  .Business-reviews {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    text-align: right;
  }
  
  .Business-reviews h3 {
    color: #CCA353;
    font-weight: 600;
  }
  
  .Business-reviews .rating {
    font-size: .88rem;
    line-height: 1rem;
  }

Thanks for all the support.

I used both of these files and they didn’t change my results:

This means that it’s something else up the line is causing your style issues. With CSS styling inheritance and specificity, it has to be one of the other files you recently worked on (assuming your test data when you were on earlier steps of the project rendered correctly)

I got it and it works! Thank you all for taking the time to answer my questions.