初次加载资源时无法正常加载,需要多次刷新、请求才能拿到资源的有效解决方案
前言
在使用cloudinary进行图片上传并获取图片链接作为用户头像时发现,图片链接网址初次加载会报错:ERR_CONNECTION_RESET
必须刷新几次才能获取到,原因可能是cloudinary没有国内的节点,而我用的是在新加坡的节点,所以会导致初次加载的时候被重定向。而这个错误会直接导致用户头像无法加载,因为在img中此链接只会被在初始化的时候加载一次,而此博客就是为了解决此问题让图片正常加载。
正文
我的思路就是监听图片地址是否能正常获取,若是获取失败则一直刷新直到图片正常加载,具体看下面代码:
修改前:
import { signOut, useSession } from 'next-auth/react';
import Link from 'next/link'
import React from 'react'
import { SessionData } from '../lib/type';
import { Logout } from '@mui/icons-material';
const handleLogout = () => {
signOut({ callbackUrl: '/auth/login' });
}
const TopBar = () => {
const { data: session } = useSession();
const user = session?.user as SessionData | null;
return (
<div className='bg-white h-9 border-x-1 flex justify-between'>
<p className='text-center mt-2 ml-2 font-sans text-small antialiased font-bold'>NextChat</p>
<div className='flex'>
<Link rel="stylesheet" href="/chats/profile">
<img
src={user?.image || "/images/person.jpg"}
alt="image"
className="w-8 h-8 rounded-full mt-[2px]"
/>
</Link>
<div className='mx-4'>
<p className='text-center font-sans text-small antialiased font-bold'>{user?.username}</p>
<p className='text-center font-sans text-mm antialiased font-bold text-gray-500'>{user?.email}</p>
</div>
<Logout sx={{ color: "#737373", cursor: "pointer" }} onClick={handleLogout} className='mt-1 mr-4'/>
</div>
</div>
)
}
export default TopBar
修改后:
import { signOut, useSession } from 'next-auth/react';
import Link from 'next/link'
import React, { useEffect, useRef } from 'react'
import { SessionData } from '../lib/type';
import { Logout } from '@mui/icons-material';
const handleLogout = () => {
signOut({ callbackUrl: '/auth/login' });
}
const TopBar = () => {
const { data: session } = useSession();
const user = session?.user as SessionData | null;
const imageRef = useRef<HTMLImageElement | null>(null);
const handleImageError = () => {
if (imageRef.current) {
imageRef.current.src = user?.image || "/images/person.jpg";
}
};
useEffect(() => {
if (imageRef.current) {
imageRef.current.onerror = handleImageError;
}
}, [user?.image]);
return (
<div className='bg-white h-9 border-x-1 flex justify-between'>
<p className='text-center mt-2 ml-2 font-sans text-small antialiased font-bold'>NextChat</p>
<div className='flex'>
<Link rel="stylesheet" href="/chats/profile">
<img
ref={imageRef}
src={user?.image || "/images/person.jpg"}
alt="image"
className="w-8 h-8 rounded-full mt-[2px]"
/>
</Link>
<div className='mx-4'>
<p className='text-center font-sans text-small antialiased font-bold'>{user?.username}</p>
<p className='text-center font-sans text-mm antialiased font-bold text-gray-500'>{user?.email}</p>
</div>
<Logout sx={{ color: "#737373", cursor: "pointer" }} onClick={handleLogout} className='mt-1 mr-4'/>
</div>
</div>
)
}
export default TopBar
在这个修改后的代码中,我定义了一个名为 imageRef
的 useRef
来存储图像元素的引用。然后,我使用 useEffect
钩子来监听 user?.image
的变化,并在其变化时更新图像的 onerror
事件处理函数。当图像加载失败时,handleImageError
函数会被调用(给onerror绑定处理函数),重新设置图像的 src
属性为原始的 user?.image
或默认图片的路径,如果在处理函数 handleImageError
中将图片 src
重新设置为另一个同样会加载失败的图片地址,这会再次触发 onerror
事件。这样图片就会一直尝试重新加载,直到成功为止。