首页 > 解决方案 > 根据下拉列表从 2 个 API 和 setState 获取详细信息 - React 功能组件

问题描述

我有一个名为 Calendar 的功能组件,其中每个月都是一个按钮。我设计了两个 API:

  1. 第一个在第一次加载时从 API 中获取数据,并且没有从下拉列表中选择任何内容。以下是 Postman 上的输出:

     [
     { 
         "month": 1,
         "count": 5
     },
     {
        "month": 3,
        "count": 2
     },
     {
         "month": 10,
         "count": 4
     },
     {
         "month": 11,
         "count": 3
     }
    

    ]`

现在我有以下状态,

        const [jan, setJan] = useState(0);
        const [feb, setFeb] = useState(0);
        const [mar, setMar] = useState(0);
        const [apr, setApr] = useState(0);
        const [may, setMay] = useState(0);
        const [june, setJune] = useState(0);
        const [july, setJuly] = useState(0);
        const [aug, setAug] = useState(0);
        const [sept, setSept] = useState(0);
        const [oct, setOct] = useState(0);
        const [nov, setNov] = useState(0);
        const [dec, setDec] = useState(0);
        const [month, setMonth] = useState([]);
        const cleanup = () =>{
                 setJan(0);
                 setFeb(0);
                 setMar(0);
                 setApr(0);
                 setMay(0);
                 setJune(0);
                 setJuly(0);
                 setAug(0);
                 setSept(0);
                 setOct(0);
                 setNov(0);
                 setDec(0);
}
    const [month, setMonth] = useState([]);
    const [name, setName] = useState("");

每个月的状态应该根据下拉列表改变,如果我选择一个学生说Rani,应该显示她每个月的总分,如果我选择Ramu,他的分数应该显示在按钮上。现在,我有 2 个不同的 API,如果没有选择名称,则默认 api 获取信息,如果没有,另一个具有 studentname 的 api 根据选择的学生获取信息。

假设,我从下拉列表中选择 Rani,并根据下面给出的 API 输出:

[
    {
        "month": 11,
        "count": 1
    }
]

只有 11 月按钮应显示计数为 1,其余为 0。如果我未在下拉列表中选择任何内容,则默认 API 应该可以工作。我设计了下面的代码,它在正确加载时显示通知的数量,但是一旦我更改名称并且再次不选择任何内容,所有月份它都显示为 0。下面是相同的 useEffect 代码。

  useEffect(() => {
    if(name!=""){
        cleanup();
        axios.get("http://localhost:8081/api/teacherportal/1234/${name}")
            .then(res => {
                setMonth(res.data)
                month.forEach(mon => {
                    {
                        (month.map(mon => {
                            if (mon["month"] === 1)
                                setJan(mon["count"]);
                            else if (mon["month"] === 2)
                                setFeb(mon["count"]);
                            else if (mon["month"] === 3)
                                setMar(mon["count"]);
                            else if (mon["month"] === 4)
                                setApr(mon["count"]);
                            else if (mon["month"] === 5)
                                setMay(mon["count"]);
                            else if (mon["month"] === 6)
                                setJune(mon["count"]);
                            else if (mon["month"] === 7)
                                setJuly(mon["count"]);
                            else if (mon["month"] === 8)
                                setAug(mon["count"]);
                            else if (mon["month"] === 9)
                                setSept(mon["count"]);
                            else if (mon["month"] == 10)
                                setOct(mon["count"]);
                            else if (mon["month"] === 11)
                                setNov(mon["count"]);
                            else if (mon["month"] === 12)
                                setDec(mon["count"]);

                        }
                        ))
                    }
                })
            })
            .catch(err => { console.log(err) })
        }
    else{
       
     axios.get("http://localhost:8081/api/teacherportal/1234")
        .then(res => {
            setMonth(res.data)
            month.forEach(mon => {
                {
                    (month.map(mon => {
                        if (mon["month"] === 1)
                            setJan(mon["count"]);
                        else if (mon["month"] === 2)
                            setFeb(mon["count"]);
                        else if (mon["month"] === 3)
                            setMar(mon["count"]);
                        else if (mon["month"] === 4)
                            setApr(mon["count"]);
                        else if (mon["month"] === 5)
                            setMay(mon["count"]);
                        else if (mon["month"] === 6)
                            setJune(mon["count"]);
                        else if (mon["month"] === 7)
                            setJuly(mon["count"]);
                        else if (mon["month"] === 8)
                            setAug(mon["count"]);
                        else if (mon["month"] === 9)
                            setSept(mon["count"]);
                        else if (mon["month"] == 10)
                            setOct(mon["count"]);
                        else if (mon["month"] === 11)
                            setNov(mon["count"]);
                        else if (mon["month"] === 12)
                            setDec(mon["count"]);

                    }
                    ))
                }
            })
        })
        .catch(err => { console.log(err) })
    }
}, [month,name]);

下面是下拉 onChange 处理程序:

const handleChange = (event) => {

        setCustomer(event.target.value);
        if (event.target.value === "Rani") {
            setName("Rani");
        }
        else if (event.target.value === "Ramu") {
            setName("Ramu");
        }
        else if (event.target.value === "Lalu") {
            setName("Lalu");
        }
    }

如果我从下拉列表中选择学生,并且该学生的某个月份没有数据,则从默认 api 获取的数据将被覆盖而不是显示 0,因此会显示清理功能。有人可以帮忙吗,提前谢谢你:)

标签: reactjsrestgetaxiosuse-effect

解决方案


我认为问题在于你是同一个函数中的setMonthmonth变量。setMonth不会month直接更新变量,而是在下一次渲染调用中执行此操作。

setMonth要解决您的问题,请在两次调用中收到数据后绕过:

axios.get("http://localhost:8081/api/teacherportal/1234/${name}")
            .then(res => {
                res.data.forEach(mon => {

尽管此代码可能有效,但可以简化很多。

将您的月份数据存储在一个单独useState的文件中可以更容易阅读,并且意味着不再需要从月份(数字)到 setState 函数的映射。

// array with 12 entries
const [months, setMonths] = useState(Array(12).fill(0));

// jan = months[0];
// feb = months[1];
// ...

在您的useEffect钩子中,处理 API 响应的代码是相同的。您可以删除很多代码(并使用上面的单个 useState)使其看起来像这样:

useEffect(() => {
  const getData = async () => {
    if (name !== '') {
      return axios.get('http://localhost:8081/api/teacherportal/1234/${name}');
    }

    return axios.get('http://localhost:8081/api/teacherportal/1234');
  };

  getData()
    .then(({ data }) => {
      // start with empty months data (same as `cleanup()`)
      const monthsData = Array(12).fill(0);

      // populate the new array with your API data
      data.forEach(entry => {
        // the API returns the month starting from 1, while the array index starts from 0.
        monthsData[entry.month - 1] = entry.count;
      });

      setMonths(monthsData);
    })
    .catch(error => {
      console.log('Failed to get data', error)
    });
}, [name]);

最后,handleChange 函数可以简化为:

const handleChange = (event) => {
  setCustomer(event.target.value);
  setName(event.target.value);
}

推荐阅读