我这里有一个从 pokeAPI 获取数据的函数,但我想将 IsLoading 状态设置为 true,直到所有卡片都已渲染。我在下面所做的事情似乎有时有效,有时无效。我对反应还很陌生,所以我不太确定要问什么以及需要什么更多信息,所以请让我知道。
useEffect(() => {
setIsLoading(true);
async function fetchAllPokemonData() {
try {
if (search) {
const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${search}`);
const data = await res.json();
setData([]);
setData([data]);
} else {
for (let i = 0; i < pokemon.length; i++) {
const res = await fetch(pokemon[i].url);
const data = await res.json();
setData((prev) => [...prev, data]);
if (filter) {
setData((data) =>
data.filter((item) =>
item.types.some((type) =>
type.type.name === filter)));
}
}
}
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
}
fetchAllPokemonData();
}, [pokemon, search, filter]);
尝试使用 try、catch 和finally,但它有时会起作用,有时它只是立即将 isLoading 设置回 false,或者当并非所有卡片都已生成时。
没什么可看的。然后不确定具体的问题,如果你做一个沙箱什么的看看就容易多了。可以在codesandbox或playcode上制作,甚至不需要登录playcode。
我要做的第一件事,并且我认为这通常是最佳实践,是将获取与状态设置分开。它使更改变得更容易,尤其是在 React 中,你必须遵循钩子规则。你可以在 React 文档上查找 hooks 规则,我认为它解释得相当好。
特别是在这种情况下,有时您有条件地调用钩子,这违反了钩子规则,它不会可靠地工作。
...
if (filter) {
setData((data) =>
data.filter((item) =>
...
在 for 循环中也有对
setData
的调用,每次渲染需要调用 hook 相同的次数。
因此,您可以进行一些更改,以便代码遵循挂钩规则。但通常来说,如果您考虑如何组织和拆分代码,您应该放置一个可以更轻松地满足钩子规则或任何框架中的任何规则的位置。
在这里,以及在某些情况下,将口袋妖怪的获取与状态设置分开是有益的。因此,您可以这样想:您需要一个旨在根据某些输入获取某些数据的函数,并且理想情况下该函数始终以相同的可靠格式返回数据。在这种情况下,它可能是一个神奇宝贝数组,或者一个错误,或者未定义,或者一个神奇宝贝或错误的数组,或者一个仅代表成功获取的数组,或者其他东西,但这取决于你想要如何设计它。
不幸的是,在 React 中你不能使用异步效果函数参数,所以你仍然必须在你创建的异步函数中设置状态,这已经很棒了。但您仍然可以分离获取逻辑,并且必须这样做才能使钩子发挥作用。
重要的是你知道需要什么数据,在这里,在 React 的上下文中,任何条件逻辑都应该发生在状态设置函数内。因此,在您的示例中,获取逻辑可能如下所示
async function fetchAllPokemonData() {
async function getData() {
let results = [];
for (let i = 0; i < pokemon.length; i++) {
const res = await fetch(pokemon[i].url)
.catch((e) => console.log(e))
.then((res) => {
//any processing you want to do on result
return res;
});
}
}
const data = getData();
setData(data);
}
因此
getData
函数仅返回成功获取的神奇宝贝的数组。并且您设置一次状态,它将始终设置状态。