关于 API 使用 .then 和 useEffect 获取订单的问题
Question about API fetch order using .then and useEffect
我有一个关于 API 使用 .then 和 useEffect 获取订单的问题。我会尽力向大家解释,以获得一些有用的建议。
代码的预期结果:
第一次加载时(第一次访问该站点时),我希望索引为 1 的神奇宝贝显示为默认值(因此,我设置默认值的原因状态变量“pokemonIndex”为 1。但没有任何显示..
每次单击将切换 toggle() 函数的按钮时,它都会呈现 getRandomIndex() 函数,更新状态变量“pokemonIndex”,这将 运行 useEffect .
useEffect 将使用更新后的 ${pokemonIndex}
获取新的 API
代码的其余部分似乎不言自明。
这些是我的问题:
在上面的第 1 步中,为什么即使我将默认状态变量设置为 1 也没有任何显示?
每次我点击 运行 的 toggle() 按钮时,它都会获取一个新的 API。但是,网络选项卡如下所示:
chrome network tab image
- (请参考图片)蓝线表示每次点击按钮获取的数据(第一个是第一次加载时获取的 API - 问题 1)。不过,好像有点不对。例如,在第一次点击时,它会获取 ID 为 342 的口袋妖怪,但也会获取 ID 为 1 的口袋妖怪图像。存在“不匹配”。我期望的是单击按钮,它将获取(例如)一个 ID 为 55 的口袋妖怪以及一个 ID 为 55 的口袋妖怪图像(就像我画的蓝线)
-> 这是正常行为吗?或者我的代码有什么问题。感谢您阅读这么长的解释。提前致谢!
export default function Testing() {
const [randomPokemon, setRandomPokemon] = React.useState({})
const [specifics, setSpecifics] = React.useState({})
const [pokemonIndex, setPokemonIndex] = React.useState(1)
const [prevPokemonIndex, setPrevPokemonIndex] = React.useState(0)
const [disableButton, setDisableButton] = React.useState(false)
function disableBtn() {
setDisableButton(prevState => !prevState);
setTimeout((setDisableButton), 1500)
}
function getRandomIndex(lowerBound, upperBound) {
return Math.floor(Math.random() * (upperBound - lowerBound + 1)) + lowerBound;
};
function toggle(e) {
e.preventDefault()
const randomIndex = getRandomIndex(1, 898);
setPokemonIndex(randomIndex);
disableBtn()
}
React.useEffect(() => {
fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonIndex}/`)
.then(res => res.json())
.then(data => {
setRandomPokemon(data);
setSpecifics({
pokemonName: randomPokemon.name,
pokemonId: randomPokemon.id,
pokemonType: randomPokemon.types ? randomPokemon.types.map(type => type.type.name) : [],
pokemonAbility: randomPokemon.abilities ? randomPokemon.abilities.map(ability => ability.ability.name) : [],
pokemonImage: randomPokemon.sprites ? randomPokemon.sprites.other[`official-artwork`].front_default : []
});
})
}, [pokemonIndex])
return (
<div>
<form>
<button onClick={toggle} disabled={disableButton} type="button">Click me</button>
<img src={specifics.pokemonImage}></img>
<span>{specifics.pokemonName}</span>
<span>{specifics.pokemonId}</span>
<span>{specifics.pokemonType}</span>
<span>{specifics.pokemonAbility}</span>
</form>
</div>
)
这里的问题是您依赖 randomPokemon
,状态原子,在 then
处理程序中。
但是React中的setState
是异步的,所以randomPokemon
不会在setRandomPokemon
之后执行setSpecifics
的时候发生变化,所以具体是始终根据效果调用时的数据计算(实际上 (heh) 是 just-loaded 数据后的一个“步骤”)。
您应该在该函数中使用 data
(这是您刚刚加载的新数据)——或者,因为 specifics
是根据 randomPokemon
严格计算的,它根本不需要是状态原子,但可以使用 useMemo
导出,如下所示:
function getRandomIndex(lowerBound, upperBound) {
return Math.floor(Math.random() * (upperBound - lowerBound + 1)) + lowerBound;
}
export default function Testing() {
const [pokemon, setPokemon] = React.useState(null); // Nothing loaded yet
const [pokemonIndex, setPokemonIndex] = React.useState(1); // Which pokemon to load
const [disableButton, setDisableButton] = React.useState(false);
function disableBtn() {
setDisableButton(true);
setTimeout(() => setDisableButton(false), 1500);
}
function loadRandomPokemon(e) {
e.preventDefault();
const randomIndex = getRandomIndex(1, 898);
setPokemonIndex(randomIndex);
disableBtn();
}
React.useEffect(() => {
fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonIndex}/`)
.then((res) => res.json())
.then(setPokemon);
});
const specifics = React.useMemo(() => {
if (!pokemon) {
return null; // Not loaded, no specifics yet
}
return {
pokemonName: pokemon.name,
pokemonId: pokemon.id,
pokemonType: pokemon.types ? pokemon.types.map((type) => type.type.name) : [],
pokemonAbility: pokemon.abilities ? pokemon.abilities.map((ability) => ability.ability.name) : [],
pokemonImage: pokemon.sprites ? pokemon.sprites.other[`official-artwork`].front_default : [],
};
}, [pokemon]);
// ...
}
React.useEffect(() => {
fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonIndex}/`)
.then(res => res.json())
.then(data => {
setSpecifics({
pokemonName: data.name,
pokemonId: data.id,
pokemonType: data.types ? data.types.map(type => type.type.name) : [],
pokemonAbility: data.abilities ? data.abilities.map(ability => ability.ability.name) : [],
pokemonImage: data.sprites ? data.sprites.other[`official-artwork`].front_default : []
});
})
}, [pokemonIndex])
试试这个。这对你有用。
我有一个关于 API 使用 .then 和 useEffect 获取订单的问题。我会尽力向大家解释,以获得一些有用的建议。
代码的预期结果:
第一次加载时(第一次访问该站点时),我希望索引为 1 的神奇宝贝显示为默认值(因此,我设置默认值的原因状态变量“pokemonIndex”为 1。但没有任何显示..
每次单击将切换 toggle() 函数的按钮时,它都会呈现 getRandomIndex() 函数,更新状态变量“pokemonIndex”,这将 运行 useEffect .
useEffect 将使用更新后的 ${pokemonIndex}
获取新的 API代码的其余部分似乎不言自明。
这些是我的问题:
在上面的第 1 步中,为什么即使我将默认状态变量设置为 1 也没有任何显示?
每次我点击 运行 的 toggle() 按钮时,它都会获取一个新的 API。但是,网络选项卡如下所示: chrome network tab image
- (请参考图片)蓝线表示每次点击按钮获取的数据(第一个是第一次加载时获取的 API - 问题 1)。不过,好像有点不对。例如,在第一次点击时,它会获取 ID 为 342 的口袋妖怪,但也会获取 ID 为 1 的口袋妖怪图像。存在“不匹配”。我期望的是单击按钮,它将获取(例如)一个 ID 为 55 的口袋妖怪以及一个 ID 为 55 的口袋妖怪图像(就像我画的蓝线)
-> 这是正常行为吗?或者我的代码有什么问题。感谢您阅读这么长的解释。提前致谢!
export default function Testing() {
const [randomPokemon, setRandomPokemon] = React.useState({})
const [specifics, setSpecifics] = React.useState({})
const [pokemonIndex, setPokemonIndex] = React.useState(1)
const [prevPokemonIndex, setPrevPokemonIndex] = React.useState(0)
const [disableButton, setDisableButton] = React.useState(false)
function disableBtn() {
setDisableButton(prevState => !prevState);
setTimeout((setDisableButton), 1500)
}
function getRandomIndex(lowerBound, upperBound) {
return Math.floor(Math.random() * (upperBound - lowerBound + 1)) + lowerBound;
};
function toggle(e) {
e.preventDefault()
const randomIndex = getRandomIndex(1, 898);
setPokemonIndex(randomIndex);
disableBtn()
}
React.useEffect(() => {
fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonIndex}/`)
.then(res => res.json())
.then(data => {
setRandomPokemon(data);
setSpecifics({
pokemonName: randomPokemon.name,
pokemonId: randomPokemon.id,
pokemonType: randomPokemon.types ? randomPokemon.types.map(type => type.type.name) : [],
pokemonAbility: randomPokemon.abilities ? randomPokemon.abilities.map(ability => ability.ability.name) : [],
pokemonImage: randomPokemon.sprites ? randomPokemon.sprites.other[`official-artwork`].front_default : []
});
})
}, [pokemonIndex])
return (
<div>
<form>
<button onClick={toggle} disabled={disableButton} type="button">Click me</button>
<img src={specifics.pokemonImage}></img>
<span>{specifics.pokemonName}</span>
<span>{specifics.pokemonId}</span>
<span>{specifics.pokemonType}</span>
<span>{specifics.pokemonAbility}</span>
</form>
</div>
)
这里的问题是您依赖 randomPokemon
,状态原子,在 then
处理程序中。
但是React中的setState
是异步的,所以randomPokemon
不会在setRandomPokemon
之后执行setSpecifics
的时候发生变化,所以具体是始终根据效果调用时的数据计算(实际上 (heh) 是 just-loaded 数据后的一个“步骤”)。
您应该在该函数中使用 data
(这是您刚刚加载的新数据)——或者,因为 specifics
是根据 randomPokemon
严格计算的,它根本不需要是状态原子,但可以使用 useMemo
导出,如下所示:
function getRandomIndex(lowerBound, upperBound) {
return Math.floor(Math.random() * (upperBound - lowerBound + 1)) + lowerBound;
}
export default function Testing() {
const [pokemon, setPokemon] = React.useState(null); // Nothing loaded yet
const [pokemonIndex, setPokemonIndex] = React.useState(1); // Which pokemon to load
const [disableButton, setDisableButton] = React.useState(false);
function disableBtn() {
setDisableButton(true);
setTimeout(() => setDisableButton(false), 1500);
}
function loadRandomPokemon(e) {
e.preventDefault();
const randomIndex = getRandomIndex(1, 898);
setPokemonIndex(randomIndex);
disableBtn();
}
React.useEffect(() => {
fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonIndex}/`)
.then((res) => res.json())
.then(setPokemon);
});
const specifics = React.useMemo(() => {
if (!pokemon) {
return null; // Not loaded, no specifics yet
}
return {
pokemonName: pokemon.name,
pokemonId: pokemon.id,
pokemonType: pokemon.types ? pokemon.types.map((type) => type.type.name) : [],
pokemonAbility: pokemon.abilities ? pokemon.abilities.map((ability) => ability.ability.name) : [],
pokemonImage: pokemon.sprites ? pokemon.sprites.other[`official-artwork`].front_default : [],
};
}, [pokemon]);
// ...
}
React.useEffect(() => {
fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonIndex}/`)
.then(res => res.json())
.then(data => {
setSpecifics({
pokemonName: data.name,
pokemonId: data.id,
pokemonType: data.types ? data.types.map(type => type.type.name) : [],
pokemonAbility: data.abilities ? data.abilities.map(ability => ability.ability.name) : [],
pokemonImage: data.sprites ? data.sprites.other[`official-artwork`].front_default : []
});
})
}, [pokemonIndex])
试试这个。这对你有用。