React中forEach调用getDownloadURL时状态更新不触发渲染问题
问题核心原因
代码无法正常渲染由3个明确错误导致:
getDownloadURL是异步Promise方法,forEach遍历不会等待内部Promise执行完成,代码会直接执行setresObj更新状态,此时存储结果的数组还是空的- 组件顶层声明的普通数组变量会在每次组件重渲染时被重置,且原代码存在变量名拼写问题,
result和result1混用 - 渲染逻辑中
map遍历的箭头函数使用大括号包裹JSX但没有写return返回元素,遍历结果全为undefined,同时key属性为空,不符合React渲染规则
修复实现
核心思路是用Promise.all等待所有异步封面请求全部完成后,再一次性更新组件状态,避免异步时序问题;同时修正渲染语法错误。
import { useState, useEffect } from 'react'; import { ref, getDownloadURL } from 'firebase/storage'; // 提前导入项目中已初始化完成的firebase storage实例 // 无封面时的占位图,可替换为项目本地静态资源 const DEFAULT_COVER = "https://upload.wikimedia.org/wikipedia/commons/a/ac/No_image_available.svg"; function BookList(props) { // 状态初始值设为空数组,省去额外的空值判断 const [resObj, setResObj] = useState([]); useEffect(() => { // 封装单本图书的封面获取逻辑 const getSingleBookCover = async (bookItem) => { const imgPath = `bookDB/${bookItem.도서번호}.jpg`; const imgRef = ref(storage, imgPath); try { const coverUrl = await getDownloadURL(imgRef); return { ...bookItem, bookUrl: coverUrl }; } catch (error) { if (error.code === 'storage/object-not-found') { return { ...bookItem, bookUrl: DEFAULT_COVER }; } console.log(error); return { ...bookItem, bookUrl: DEFAULT_COVER }; } }; const loadBookList = async () => { // 并行请求所有图书封面,全部完成后再更新状态 const bookListWithCover = await Promise.all( props.resObj.map(book => getSingleBookCover(book)) ); setResObj(bookListWithCover); }; // 仅当props传入有效图书数组时执行加载 if (props.resObj?.length) { loadBookList(); } }, [props.resObj]); // 依赖项加入传入的图书数组,props更新时自动同步数据 return ( <div> {resObj.map(item => ( <img key={item.도서번호} // 用图书唯一编号作为key,不要留空 className='~~' onClick={() => { // 补充你的点击业务逻辑 }} src={item.bookUrl} alt={item.도서명 || '图书封面'} /> ))} </div> ); } export default BookList;
注意事项
- 不要在组件顶层或useEffect中用普通变量存储跨渲染周期的数据,所有需要触发视图更新的数据必须存在
useState中 - 处理批量异步请求时,不要用
forEach配合外部数组push的写法,直接用Promise.all并行等待所有请求完成再更新状态,性能更好且不会出现时序错乱 - JSX遍历渲染时,如果箭头函数后直接写元素,用圆括号包裹即可;如果用大括号包裹逻辑,必须手动写
return返回要渲染的元素 - useEffect不要留空依赖数组,需要把用到的外部变量(比如这里的props.resObj)加入依赖项,避免数据更新后视图不刷新
注:代码中的默认封面地址可替换为你项目本地的占位图资源,避免依赖外部资源。
内容的提问来源于stack exchange,提问作者huni1023
相关产品推荐
相关产品推荐

