Search code examples
javascriptreactjsapireact-hooksmap-function

TypeError: food.map is not a function in Reactjs


I am new to Reactjs. I am using React hooks and axios to fetch an api of a single post data from its id. I called the api and passed the data into child components using props through spread operator. The server runs but on the page it renders the above error. I have used the map function correctly, but it says map is not a function. I checked the issues online, where the users having similar problem says the data may not be an array. It should be an array but different data types like id,name,title,price etc in my case.

My FoodPage.js

function Food() {

  const [food, setFood] = useState([])
  const [id,setId] = useState(1)

  useEffect(() => {
    axios.get(`https://exampleurl.herokuapp.com/api/menus/${id}`)
    .then(abc=>{
      console.log(abc.data)
      setFood(abc.data)
    })
    .catch(err =>{
      console.log(err) 
    })
  }, [])


 return (
  <div>
    <div className="food-page">         
         {food.map((foodItem) => {
            return <PageHeader  {...foodItem} key={foodItem.id} />;
          })}
           <Customize />
          {food.map((foodItem) => {
            return <FoodDescription  {...foodItem} key={foodItem.id} />;
          })}       
    </div>
  </div>
  );
}

export default Food;

My FoodDescription:

function FoodDescription(props) {

  console.log(props);
  const {food_name,long_title,subtitle,description,price,id} = props;

  return (
    <div className="food-description">
        <div className="container">
          <div className="title">
            <div className="main-title">{food_name}</div>
          </div>
          <div className="description">
            {/* {description.map((des: string, index: number) => { */}
            {description.map((des, index) => {  
              return <p key={index}>{des}</p>;
            })}
          </div>
          <div className="order">
            <div className="quantity">
              <div className="negative" onClick={() => this.handleDecrement()}>
                -
              </div>
              {this.state.quantity}
              <div className="positive" onClick={() => this.handleIncrement()}>
                +
              </div>
            </div>
            <ExploreButton active="link-active">
              Add to Order -{price}
            </ExploreButton>
          </div>
        </div>
      </div>
  )
}

export default FoodDescription;

Update

The abc.data in console gives the following:

enter image description here


Solution

  • According to your API result, when you call

    https://texas-crm1.herokuapp.com/api/menus/1 it return an object, not an array.

    {
        "id": 1,
        "category": "main courses",
        "image": "imgUrl",
        "image_url": "imgUrl",
        "food_name": "butter chicken",
        "subtitle": null,
        "long_title": null,
        "description": "<p>this is a test data from backend for butter chicken in main courses.</p>",
        "price": 49.0,
        "rating": 3.0
    }
    

    So you don't need to map over food try this :

    function Food() {
    
      const [food, setFood] = useState([])
      const [id,setId] = useState(1)
    
      useEffect(() => {
        axios.get(`https://texas-crm1.herokuapp.com/api/menus/${id}`)
        .then(abc=>{
          console.log(abc.data)
          setFood(abc.data)
        })
        .catch(err =>{
          console.log(err) 
        })
      }, [])
    
    
     return (
      <div>
        <div className="food-page">         
           <PageHeader  {...food} key={food.id} />;
           <Customize />
           <FoodDescription  {...food} key={food.id} />;
        </div>
      </div>
      );
    }
    
    export default Food;