映射不是使用反应钩子的函数

时间:2021-02-01 22:32:17

标签: reactjs function dictionary react-hooks

我正在尝试使用来自 API 调用的名称填充选择栏。我已经创建了我的钩子,也使用了它的副作用,并将数据向下传递。它给我的地图不是函数错误。我的变量是一个空数组,但变量的设置者没有将值分配给我的变量。如何清除地图而不是功能错误?我附上了我的片段。谢谢。

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

2 个答案:

答案 0 :(得分:2)

首先,这里

setIngredients(res.data);

res.data 更改为 res.ingredients(响应对象没有 data 属性)。然后你会面临另一个错误,

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

首先,ingredient.name 是未定义的,其次,如果它存在,它可能是一个字符串。只需在此处放弃 setIngredients 调用。

答案 1 :(得分:1)

您将 displayIngredients 声明为数组的变量 typeof(通过直接影响 array.map() 结果)。你需要它是一个返回数组的函数,如下所示:

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

您还应该等待 API 调用结束,然后再显示您的选择,以防止数据加载时出现空白结果(如果有很多)。最简单的方法是在 API 调用运行时返回一个加载器:

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

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