简体   繁体   English

为什么我的 state 仅在第二次 state 更改时更新,而不是第一次 state 在 React 中随 useEffect 更改而更新?

[英]Why is my state only updated on the second state change instead of first state change with useEffect in React?

I made a search bar that allows the user to search all sports available in one specific city (if sport is not defined) or a specific sport in a specific city (if sport is defined).我制作了一个搜索栏,允许用户搜索一个特定城市(如果未定义运动)或特定城市中的特定运动(如果定义了运动)中的所有可用运动。 City will allways be defined.城市总会被定义。

I put 2 inputs (city and sport) on my searchbar and I want immediate results (so that there is a request to my API without any button "search" that triggers the request).我在我的搜索栏上放了 2 个输入(城市和运动),我想要立即得到结果(这样就有一个对我的 API 的请求,而没有任何触发请求的按钮“搜索”)。

So when the user types something on the city input it triggers a request to the API and when he types something on the sport input it retriggers the request but this time with the city and the sport defined.因此,当用户在城市输入上键入内容时,它会触发对 API 的请求,当他在运动输入上键入内容时,它会重新触发请求,但这次是定义了城市和运动。 Both inputs values are store in states (city and sport).两个输入值都存储在状态(城市和运动)中。

I manage to do something that seems to work, the only problem is that if I types a sport in my input search, it does not update my request to the API.我设法做了一些似乎可行的事情,唯一的问题是,如果我在输入搜索中键入一项运动,它不会更新我对 API 的请求。 I have to retype the sport in my input a second time so that the request is updated.我必须再次在我的输入中重新输入这项运动,以便更新请求。 I don't know why it does not update the first time I types something in my sport input because I have specified on my useEffect array that it must re render when the sport state changes.我不知道为什么我第一次在我的运动输入中输入内容时它没有更新,因为我在我的 useEffect 数组上指定了它必须在运动 state 更改时重新渲染。

Can someone help me understand this?有人可以帮我理解这一点吗?

My code:我的代码:

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;

Since you are having two useEffect and one is setting city and sport you would need to make debounce for making a call for fetching list by itself.由于您有两个useEffect并且一个正在设置citysport ,因此您需要进行 debounce 以自行调用获取列表。

I would suggest that you firstly make changes to your use effect for API call fetchDataRequest :我建议您首先对 API 调用fetchDataRequest的使用效果进行更改:

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

You would listen to the actual data from BE, not from input that you fill.您将聆听来自 BE 的实际数据,而不是来自您填写的输入。

And secondly you can use library useDebounce from here https://www.npmjs.com/package/use-debounce and use useDebounceCallback to delay calling API call after you select sport/city.其次,您可以从这里https://www.npmjs.com/package/use-debounce使用库useDebounce并使用useDebounceCallback来延迟调用 API 在您 Z99938282F040718542ZEFEcity.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM