0

i'm trying to populate a select bar with a name from an API call. I Have created my hook, also useEffect for its side effects, and passed the data down the return. its giving me map is not a function error. my variable is an empty array but the setter of the variable is not assigning the value to my variable. How can i clear the map not a function error ? i have attached my snippet. Thanks.

import React, { useEffect, useState } from "react";
import axios from "axios";

const Sidebar = () => {
  const [ingredients, setIngredients] = useState([]);

  useEffect(() => {
    const fetchIngredients = async (url) => {
      try {
        let res = await axios.get(url);
        setIngredients(res.data);
      } catch (error) {
        setIngredients([]);
        console.log(error);
      }
    };
    fetchIngredients(
      "https://www.thecocktaildb.com/api/json/v2/1/search.php?i=vodka"
    );
  }, []);


  const displayIngredients = ingredients.map((ingredient) => {
    setIngredients(ingredient.name);
    return <option key={ingredient.name}>{ingredients}</option>;
  });

  return (
    <div className="sidebar">
      <label>
        By ingredient:
        <select>{displayIngredients}</select>
      </label>
    </div>
  );
};

export default Sidebar
3
  • Can you put console.log(res.data) right before setIngredients(res.data); and post what you see here? Commented Feb 1, 2021 at 22:48
  • ingredients is retrieved async, this means in the first render it is undefined until the response from axios returns. You will need to check if the data has been returned before using map. Commented Feb 1, 2021 at 22:49
  • Aside from several problems with your code, I am afraid there is a more fundamental issue - you're not properly handing what your API actually returns. 1. It returns an object, not an array. 2. The data does not use the name attribute anywhere. So I would pull up that API link in your browser and really examine the returned data's content first. Commented Feb 1, 2021 at 23:20

2 Answers 2

2

First, here

setIngredients(res.data);

change res.data to res.ingredients (the response object doesn't have data property). Then you'll face another bug,

const displayIngredients = ingredients.map((ingredient) => {
    setIngredients(ingredient.name);
//...

First, ingredient.name is undefined, and second, it probably would be a string if it existed. Just ditch the setIngredients call here.

Sign up to request clarification or add additional context in comments.

1 Comment

This is incorrect. An axios response DOES have the prop data in it. The problem the OP is having is that their API call returns an object with the attribute ingredients. As such, this is what they need setIngredients(res.data.ingredients);. thecocktaildb.com/api/json/v2/1/search.php?i=vodka
1

You are declaring displayIngredients as a variable typeof array (By directly affecting the array.map() result). You need it to be a function that return an array as follow :

const displayIngredients = () => ingredients.map((ingredient) => {
    // Do not erase your previous values here
    setIngredients(previousState => [...previousState, ingredient.name]);
    // Changed it here as well, seems more logic to me
    return <option key={ingredient.name}>{ingredient.name}</option>; 
  });

You should also wait for the API call to end before to display your select to prevent a blank result while your data load (If there is a lot). The easiest way to do that is returning a loader while the API call is running :

if(!ingredients.length) {
 return <Loader />; // Or whatever you want
}

return (
    <div className="sidebar">
      <label>
        By ingredient:
        <select>{displayIngredients}</select>
      </label>
    </div>
  );

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.