我正在使用 React,我有以下代码:
const [avatarURLs, setAvatarURLs] = useState({});
const [currentTutorProfile, setCurrentTutorProfile] = useState({});
const [avatarURLsLoaded, setAvatarURLsLoaded] = useState(false); // New state
useEffect(() => {
const avatarObject = {};
const fetchAvatar = async (tutorProfile) => {
try {
if (tutorProfile) {
const response = await axios.get(
`${process.env.REACT_APP_BASE_URL}/users/${tutorProfile.owner}/avatar`,
{ responseType: "arraybuffer" }
);
const blob = new Blob([response.data], {
type: "image/png",
});
const imageUrl = URL.createObjectURL(blob);
avatarObject[tutorProfile.owner] = "imageUrl";
}
} catch (error) {
// console.error("Error fetching user avatar:", error);
}
};
tutorProfilesArray.forEach(fetchAvatar);
console.log(avatarObject); // THIS ONE
setAvatarURLs(avatarObject);
setAvatarURLsLoaded(true); // Mark that avatarURLs are loaded
}, [tutorProfilesArray]);
我有一个 console.log(avatarObject) // 这一条,测试 avatarObject 的行,我得到空对象,然后在一段时间后对象值被填充。
我注意到这种行为仅在 api 调用与 wait 一起使用时才会出现(例如:await axios.get())。当在没有等待的情况下使用 api 调用时(例如:axios.get()),avatarObject 会立即更新。这是我不明白的地方;既然使用了await,那么即使api调用完成,该行不应该以顺序(同步)方式执行吗?
这是我已经工作了几个月的副项目,我已经努力解决这个问题一周了,但无法弄清楚为什么以及如何解决这个问题。如果这恰好是您可能知道解决方案的问题,如果我能听到一些解释,我将不胜感激。
谢谢你
我正在尝试的是:循环数组并获取数组中每个元素的个人资料图片,然后使用对象将其存储到反应 useState 变量中。
问题:它确实将个人资料图片存储到 useState 变量中,但是,这是在一段时间后完成的(我假设),因此当前端最初渲染时,它看不到任何个人资料图片,因此它不渲染个人资料图片。
是和不是。事实上,
.forEach
内部的回调可以是异步的,但forEach
语句本身不能。这意味着 console.log(avatarObject);
将在 forEach
语句内的回调仍在处理时执行。这就是为什么一开始你看到一个空物体,但一段时间后你看到物体被填满了。
有一些方法可以解决这个问题:
Promise.all
与 map
map
方法的工作方式与forEach
方法类似,但不同之处在于它返回一个新数组,其中包含执行的每个回调的结果,在异步回调的情况下,结果将是Promise。鉴于此,您可以使用 Promise.all
语句等待 map
内的所有回调完成,然后再继续。就像下面这样:
useEffect(() => {
async function fetchUsersAvatarAndUpdateState() {
const avatarObject = {};
await Promise.all(
tutorProfilesArray.map(async (tutorProfile) => {
// ... code
}),
);
console.log(avatarObject); // THIS ONE
setAvatarURLs(avatarObject);
setAvatarURLsLoaded(true); // Mark that avatarURLs are loaded
}
fetchUsersAvatarAndUpdateState();
}, [tutorProfilesArray]);
for await
代替for await (...)
循环是异步的,可用于异步迭代,如下所示:
useEffect(() => {
async function fetchUsersAvatarAndUpdateState() {
const avatarObject = {};
for await (const tutorProfile of tutorProfilesArray) {
// ... code
}
console.log(avatarObject); // THIS ONE
setAvatarURLs(avatarObject);
setAvatarURLsLoaded(true); // Mark that avatarURLs are loaded
}
fetchUsersAvatarAndUpdateState();
}, [tutorProfilesArray]);
请注意,这两种解决方案之间存在一些差异。如果你想更深入地了解这一点,我建议阅读这篇文章:for wait of VS Promise.all