我在使用cloudinary(一个云图像/视频平台)的时候发现一个潜在问题:有时候获取图片地址的时候初次获取是无法正确获取到的,必须刷新一次或多次才能正确获取到图片,但是浏览器只会加载一次图片,这就会导致图片即使存在也无法正确加载从而被备用图片替换。补充一下我使用cloudinary的方式:通过cloudinary提供的上传组件实现图片上传,在图片上传的同时记录下当前上传图片的云地址并存储到数据库,每次使用云图片的时候只需要调用这个地址。
<img ref={imageRef} src={user?.image || "/images/person.jpg"} alt="image" className="w-8 h-8 rounded-full mt-[2px]" />那么如何解决前言中的问题呢?
const imageRef = useRef<HTMLImageElement | null>(null); const handleImageError = (event: React.SyntheticEvent<HTMLImageElement, Event>) => { const imgElement = event.currentTarget; imgElement.src = user?.image; }; return ( <img ref={imageRef} src={user?.image || "/images/person.jpg"} alt="image" className="w-8 h-8 rounded-full mt-[2px]" onError={handleImageError} /> );这段代码中我们给onError绑定了handleImageError事件,作用就是当user?.image图片获取错误时都会触发onError事件从而多次加载图片,这样我们就可以避免初次加载无法拿到图片的情况。这样就结束了吗?当然没有,当user?.image一直无法正确获取就会造成无限循环,所以我们要在其基础上进行循环处理:
const imageRef = useRef<HTMLImageElement | null>(null); const timerRef = useRef<NodeJS.Timeout | null>(null); // 用于存储定时器 const handleImageError = (event: React.SyntheticEvent<HTMLImageElement, Event>) => { const imgElement = event.currentTarget; // 堆代码 duidaima.com // 如果定时器已存在,说明在2s等待时间内 if (timerRef.current) { // 继续尝试原来的操作 imgElement.src = user?.image; return; } // 设置2s定时器 timerRef.current = setTimeout(() => { // 2s后直接使用备用地址 if (imgElement) { imgElement.src = "/images/person.jpg"; } // 清除定时器引用 timerRef.current = null; }, 2000); // 首次错误时也执行原操作 imgElement.src = user?.image; }; // 组件卸载时清理定时器 useEffect(() => { return () => { if (timerRef.current) { clearTimeout(timerRef.current); } }; }, []); return ( <img ref={imageRef} src={user?.image || "/images/person.jpg"} alt="image" className="w-8 h-8 rounded-full mt-[2px]" onError={handleImageError} /> );通过添加定时器,我们可以设定强制赋值备用图片地址的时间,在这里我设置的是2s可以根据各自情况修改。这样设置后,会给模板图片2s的加载时间,2s后打断。