从Firebase获取存储文件时如何避免点击标签重复展示已加载内容
问题根因
现有去重逻辑失效核心是getDownloadURL为异步接口:短时间重复点击触发多次函数调用时,第一批请求的回调还未执行、图片URL还未写入allImages数组,第二批请求的去重判断就已经完成,会同时命中indexOf(url) === -1的条件,最终导致重复插入数据。
修复方案
通过三层逻辑规避重复渲染问题:
- 新增加载状态锁,避免同时间段重复触发请求
- 新增已加载路径缓存,已经拉取完成的路径不再重复发起请求
- 用
Promise.all批量处理异步下载地址请求,统一完成后再更新数据,进一步避免并发导致的重复问题
完整修改后代码
首先新增必要的状态变量(以React为例,其他框架可对应实现同类状态):
// 加载状态锁 const [isLoading, setIsLoading] = useState(false); // 已完整加载的存储路径缓存,可根据业务需求决定是否保留 const [loadedPaths, setLoadedPaths] = useState(new Set()); const getFromFirebase = (forceRefresh = false) => { const currentPath = `${user1}/${currentItem.id}`; // 前置校验:正在加载中,或 该路径已加载且非强制刷新场景,直接终止执行 if (isLoading || (loadedPaths.has(currentPath) && !forceRefresh)) return; setIsLoading(true); const storageRef = storage.ref(currentPath); storageRef.listAll() .then(res => { // 批量生成所有图片下载地址的异步请求 const urlPromises = res.items.map(imageRef => imageRef.getDownloadURL().then(url => ({ Test: url, Test2: imageRef.name })) ) // 等待所有异步请求完成 return Promise.all(urlPromises) }) .then(imageList => { // 统一去重后更新图片列表 setImages(prev => { const existUrlSet = new Set(prev.map(item => item.Test)); const filterNewImages = imageList.filter(img => !existUrlSet.has(img.Test)); return [...prev, ...filterNewImages]; }) // 标记当前路径已完成加载 setLoadedPaths(prev => new Set(prev).add(currentPath)); }) .catch(error => { console.log(error); }) .finally(() => { // 无论请求成功失败都释放加载锁 setIsLoading(false); }); };
可选补充逻辑
如果需要切换currentItem时自动重置状态,可添加监听逻辑:
useEffect(() => { // 切换资源项时重置加载状态,可根据业务需要决定是否清空已加载的图片列表 setIsLoading(false); }, [currentItem.id])
如果仅需要避免短时间重复点击、不需要缓存已加载路径,删除loadedPaths相关的校验和更新逻辑即可。
内容的提问来源于stack exchange,提问作者Paul VI
相关产品推荐
相关产品推荐

