[英]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 ? "¯o_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
并且一个正在设置city
和sport
,因此您需要进行 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.