为什么我的状态仅在第二次状态更改时更新,而不是在 React 中使用 useEffect 进行第一次状态更改?

时间:2021-01-22 13:36:54

标签: reactjs state

我制作了一个搜索栏,允许用户搜索一个特定城市(如果未定义运动)或特定城市中的特定运动(如果定义了运动)中的所有可用运动。 城市将永远被定义。

我在搜索栏上放置了 2 个输入(城市和运动),我希望立即得到结果(以便向我的 API 发出请求,而没有任何触发请求的“搜索”按钮)。

因此,当用户在城市输入上输入内容时,它会触发对 API 的请求,当他在运动输入上输入内容时,它会重新触发请求,但这次是定义了城市和运动。 两个输入值都存储在州(城市和体育)中。

我设法做一些似乎有效的事情,唯一的问题是,如果我在输入搜索中输入一项运动,它不会更新我对 API 的请求。我必须再次在我的输入中重新输入运动,以便更新请求。 我不知道为什么我第一次在运动输入中输入内容时它不更新,因为我在 useEffect 数组中指定了当运动状态改变时它必须重新渲染。

有人能帮我理解吗?

我的代码:

import React, { useState, useEffect } from "react";
import style from "../styles/pdrs.module.css";
import axios from "axios";


import SearchBar from "../components/SearchBar";

const Pdrs = ({ setSearchCity, searchSport, setSearchSport }) => {
  // if request's result is loading
  const [isLoading, setIsLoading] = useState(false);
  // search result
  const [searchresults, setSearchresults] = useState(
    "Lancez une recherche avec au moins une ville !"
  );
  // state for the searchbar request
  const [city, setCity] = useState("");
  const [sport, setSport] = useState(0);

  // get city's id for API's request
  const fetchCity = async () => {
    setIsLoading(true);
    try {
      // city search
      const cityResponse = await axios.get(
        `${baseAPI}/city/name=${searchCity}`
      );
      const city = cityResponse.data;
      setCity(city);
      setIsLoading(false);
    } catch (error) {
      console.log(error.message);
      setIsLoading(false);
    }
  };

  //fetching sport id
  const fetchSport = async () => {
    setIsLoading(true);
    try {
      const sportResponse = await axios.get(
        `${baseAPI}/activity/name=${searchSport}`
      );
      setSport(sportResponse.data.data[0].macro_activity_id);
      setIsLoading(false);
    } catch (error) {
      console.log(error.message);
    }
  };

  //fetching final request response
  const fetchDataRequest = async () => {
    try {
      setIsLoading(true);
      const results = await axios.get(
        `${baseAPI}/pdrs?city_id=${city.id}${
          sport ? "&macro_activity_id=" + sport : ""
        }`
      );
      // manage search results
      if (results.data.nb_results === 1) {
        setSearchresults({
          data: [results.data.data],
          nb_results: 1,
        });
        setNbResults(1);
        setIsLoading(false);
      } else {
        setSearchresults(results.data);
        setNbResults(results.data.nb_results);
        setIsLoading(false);
      }
    } catch (error) {
      console.log(error.message);
      setSearchresults(
        "Sorry, nothing was found... !"
      );
    }
  };

  useEffect(() => {
    if (searchCity) {
      fetchCity();
    }
    if (searchSport) {
      fetchSport();
    }
  }, [searchCity, searchSport]);

  useEffect(() => {
    if (searchCity) {
      fetchDataRequest();
    }
  }, [searchCity, searchSport]);
  console.log(searchresults);
  return <>
    <main className={`container ${style.pdrs}`}>
      <section className={style.searchbar}>
        <SearchBar
          searchCity={searchCity}
          setSearchCity={setSearchCity}
          searchSport={searchSport}
          setSearchSport={setSearchSport}
          searchInstallation={searchInstallation}
          setSearchInstallation={setSearchInstallation}
          searchType={searchType}
          setSearchType={setSearchType}
          setPage={setPage}
        />
      </section>
      <section className={style.results}>
        {isLoading ? (
          <div>Loading...</div>
        ) : typeof searchresults === "string" ? (
          <div className={`${style.container} ${style.noResults}`}>
            <h2>{searchresults}</h2>
          </div>
        ) : (
          <>
            <div className={style.container}>
              <div className={style.resultsList}>
                {searchresults.data.map((pdrs) => {
                  return (
                 // some code displaying the result
                  );
                })}
              </div>
            </div>
          </>
        )}
      </section>
    </main>
</>;
};

export default Pdrs;

1 个答案:

答案 0 :(得分:1)

由于您有两个 useEffect 并且一个正在设置 citysport,因此您需要进行 debounce 以自行调用获取列表。

我建议您首先更改 API 调用 fetchDataRequest 的使用效果:

useEffect(() => {
  if (searchCity) {
    fetchDataRequest();
  }
}, [city, sport]);

您将听取来自 BE 的实际数据,而不是您填写的输入。

其次,您可以从这里 https://www.npmjs.com/package/use-debounce 使用库 useDebounce 并使用 useDebounceCallback 在您选择运动/城市后延迟调用 API 调用。