如何阻止多个重新渲染执行多个 api 调用 useEffect?
Posted
技术标签:
【中文标题】如何阻止多个重新渲染执行多个 api 调用 useEffect?【英文标题】:how to stop multiple re-renders from doing multiple api calls useEffect? 【发布时间】:2021-09-13 12:24:17 【问题描述】:我是响应功能组件的新手,我正在尝试在页面加载时获取多个城市的天气数据,但 useEffect 现在正在重新呈现每个调用。如何编写这样 useEffect 不会导致重新渲染?
function App()
const [data, setData] = useState([]);
const [activeWeather, setActiveWeather] = useState([]);
useEffect(() =>
const key = process.env.REACT_APP_API_KEY;
const fetchData = async (city) =>
const res = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=$city&appid=$key`);
setData((data) => [
...data,
description: res.data.weather[0].description, icon: res.data.weather[0].icon, temp: res.data.main.temp, city: res.data.name, country: res.data.sys.country, id: res.data.id ,
]);
;
const fetchCities = () =>
const cities = [fetchData("Ottawa"), fetchData("Toronto"), fetchData("Vancouver"), fetchData("California"), fetchData("London")];
Promise.all(cities).catch((err) =>
console.log(err);
);
;
fetchCities();
, []);
【问题讨论】:
【参考方案1】:您可以让fetchData
函数在不更新状态的情况下返回您需要的数据,然后您可以获取 x 数量的城市,并且仅当所有请求完成更新状态时。
请注意,如果Promise.all 内部的请求之一失败,它将转到catch
块而不返回任何数据,基本上全有或全无
const key = process.env.REACT_APP_API_KEY
const fetchCity = async city =>
const data = await axios.get(
`https://api.openweathermap.org/data/2.5/weather?q=$city&appid=$key`,
)
return
description: data.weather[0].description,
icon: data.weather[0].icon,
temp: data.main.temp,
city: data.name,
country: data.sys.country,
id: data.id,
function App()
const [cities, setCities] = useState([])
const [activeWeather, setActiveWeather] = useState([])
useEffect(() =>
const fetchCities = async () =>
const citiesData = await Promise.all(
['Ottawa', 'Toronto', 'Vancouver'].map(fetchCity),
)
setCities(prevState => prevState.concat(citiesData))
fetchCities()
, [])
【讨论】:
这是一个很好的答案!旁注:关于全有或全无方面的观点是正确的(可以使用allSettled
获得更多细粒度的信息),但是重新 "...它将进入 catch 块而不解决任何问题的承诺..." Promise.all
不解决除它自己之外的任何承诺,无论Promise.all
做什么,承诺都会解决。 Promise.all
所做的只是观察结果并履行或拒绝自己的承诺。 (关于“解决”与“履行”与“解决”,我did a blog post。)
@T.J.Crowder 是的好点,将更新答案。 (并在途中阅读帖子)【参考方案2】:
您可以使用Promise.all
,然后调用setData
一次。像这样:
useEffect(() =>
const fetchCity = (city) => axios.get(`$base/$city`);
const cities = ["Ottawa", "Toronto"];
const promises = cities.map(fetchCity);
Promise.all(promises).then((responses) =>
setData(cities.map((city, index) => ( city, ...responses[index] )));
);
, []);
【讨论】:
以上是关于如何阻止多个重新渲染执行多个 api 调用 useEffect?的主要内容,如果未能解决你的问题,请参考以下文章
React Hooks:跳过多个连续 setState 调用的重新渲染