【发布时间】:2021-09-23 19:27:22
【问题描述】:
我需要一些帮助来帮助我在 React 中进行当前项目。我正在为我的工作面试制作一个星球大战应用程序,但我遇到了一个问题。 获取效率。
我正在获取这些数据,然后再获取一些数据,因为第一个获取的数据中有 url,一切都很好,但首先我在表中看到了“url”,然后它变成了正确的数据。
当一切都正确呈现时,我想将“已获取”状态设置为 true,但我不知道该怎么做。
const api = `https://swapi.dev/api/people/`;
const [characters, setCharacters] = useState([]);
const [speciesOptions, setSpeciesOptions] = useState([]);
const [homeworldOptions, setHomeworldOptions] = useState([]);
const [fetched, setFetched] = useState(false);
useEffect(() => {
const fetchedTimeout = () => {
setTimeout(() => {
setFetched(true);
}, 2000);
};
const fetchArray = (array, arrName) => {
for (let elem of array) {
fetch(elem).then((response) =>
response.json().then((data) => {
array.shift();
array.push(data.name);
})
);
}
if (arrName === "species") {
if (!array.length) {
array.push("Unspecified");
}
}
};
async function fetchOtherData(characters) {
await characters.forEach((character) => {
const homeworld = character.homeworld;
const vehicles = character.vehicles;
const starships = character.starships;
const species = character.species;
fetch(homeworld).then((response) =>
response.json().then((data) =>
setCharacters((prevData) =>
prevData.map((prevCharacter) =>
prevCharacter.homeworld === homeworld
? {
...prevCharacter,
homeworld: data.name,
}
: prevCharacter
)
)
)
);
fetchArray(vehicles);
fetchArray(starships);
fetchArray(species, "species");
});
await setCharacters(characters);
await fetchedTimeout();
}
const fetchAllCharacters = (allCharacters, data) => {
if (data.next) {
fetch(data.next)
.then((response) => response.json())
.then((data) => {
allCharacters.push(...data.results);
fetchAllCharacters(allCharacters, data);
});
}
if (!data.next) {
fetchOtherData(allCharacters);
}
};
async function fetchApi() {
const allCharacters = [];
await fetch(api)
.then((response) => response.json())
.then((data) => {
allCharacters.push(...data.results);
fetchAllCharacters(allCharacters, data);
})
.catch((error) => console.log(error));
}
const setSpeciesFiltering = () => {
const speciesFiltering = [];
for (let character of characters) {
const characterSpecies = character.species.join();
const foundSpecies = speciesFiltering.indexOf(characterSpecies);
if (foundSpecies === -1) {
speciesFiltering.push(characterSpecies);
}
}
const speciesOptions = speciesFiltering.map((species) => (
<option value={species}>{species}</option>
));
setSpeciesOptions(speciesOptions);
};
const setHomeworldFiltering = () => {
const homeworldFiltering = [];
for (let character of characters) {
const characterHomeworld = character.homeworld;
const foundSpecies =
homeworldFiltering.indexOf(characterHomeworld);
if (foundSpecies === -1) {
homeworldFiltering.push(characterHomeworld);
}
}
const homeworldOptions = homeworldFiltering.map((homeworld) => (
<option value={homeworld}>{homeworld}</option>
));
setHomeworldOptions(homeworldOptions);
};
fetchApi();
setSpeciesFiltering();
setHomeworldFiltering();
}, []);
感谢您的回复。
好的,在所有的 cmets 之后(谢谢!)我把代码改成了这样。
useEffect(() => {
const fetchOtherData = (characters) => {
const charactersWithAllData = [];
characters.forEach((character) => {
const homeworld = character.homeworld;
const species = character.species;
const vehicles = character.vehicles;
const starships = character.starships;
let urls = [homeworld, ...species, ...vehicles, ...starships];
Promise.all(
urls.map((url) => {
if (url.length) {
fetch(url)
.then((response) => response.json())
.then((data) => {
if (url.search("species") > 0) {
character.species = data.name;
}
if (url.search("planets") > 0) {
character.homeworld = data.name;
}
if (url.search("vehicles") > 0) {
character.vehicles.shift();
character.vehicles.push(data.name);
}
if (url.search("starships") > 0) {
character.starships.shift();
character.starships.push(data.name);
}
})
.catch((err) => console.error(err));
}
if (!url.length) {
if (url.search("species")) {
character.species = "Unspecified";
}
if (url.search("vehicles")) {
character.vehicles = "";
}
if (url.search("starships")) {
character.starships = "";
}
}
})
).then(charactersWithAllData.push(character));
});
return charactersWithAllData;
};
const fetchApi = () => {
const characters = [];
Promise.all(
[api].map((api) =>
fetch(api)
.then((response) => response.json())
.then((data) => characters.push(...data.results))
.then((data) => {
setCharacters(fetchOtherData(characters));
})
)
);
};
fetchApi();
}, []);
我必须在什么时候设置“字符”状态?因为在上面的情况下,数据首先显示在屏幕上,然后设置状态。
【问题讨论】:
-
Promise.all可能会有所帮助。 -
你可以将所有的 fetch 请求映射到一个 Promises 数组和
Promise.all它们。不要将async/await与承诺链混合。Array.prototype.forEach是同步的,所以你不能await它。fetchArray函数似乎改变了传递给它的数组。此外,您不应该将 JSX 存储在状态中,即物种和家庭世界选项。存储数据并通过渲染 UI 渲染选项。 -
Drew 说了什么,但我也建议您拆分您的
useEffect钩子,每个钩子只做一件事,并让其他useEffect钩子具有适当的依赖关系。拥有 10 个独立的钩子,都做一件事,而不是 1 个巨大的钩子做十件事,这被认为是完全可以接受的做法。 -
所有这些都非常有帮助,谢谢!我已经尽我所能并理解了。你也可以看看另一个问题吗? stackoverflow.com/questions/69299486/…
标签: javascript reactjs asynchronous async-await fetch