我有以下渲染图像的逻辑,当前流如下:如果状态为false,则显示微调器,然后当图像加载时,微调器消失。
这里的核心问题是,状态是重新渲染导致图像再次加载的组件。关于如何在图像加载后进行即时切换,我有点没有选择了。
它不是循环,而是图像再次重新加载,即使由于setLoading(true)
引起的渲染而已经加载了图像。
如何防止重新加载。useEffect
逻辑只是加载图像的模拟器,但我的真实图像来自icons变量。
export const iconsImg: React.FC<Props> = ({ img: string }) => {
useEffect(() => {
let newImg = new Image();
newImg.src = icons[img].props.src;
newImg.onload = () => {
setLoading(true);
};
}, []);
const icons: iconsInterface = {
a: <img className={classes.imgStyle} alt="a" src={link} />,
b: <img className={classes.imgStyle} alt="b" src={link} />,
}
const [loading, setLoading] = useState(false);
return (
<React.Fragment>
{!loading ? (
<Spinner>
) : (
icons[img]
)}
</React.Fragment>
)}
问题
上一次尝试的问题是,您从显示Spinner
的loading
开始,并且您试图在加载映像后切换状态,但这种情况永远不会发生,因为映像没有安装在DOM中。
创建icons
并不等同于创建img
,直到它被添加到return
中并安装到DOM中。我认为它加载了两次,因为在某个时刻,您直接或在loading
更改后将其中两个添加到DOM中。
解决方案
您可以简化您的组件,如下所示。注意,我在创建图像时删除了icons
并设置了alt
属性(两者之间的一个区别(。那个setTimeout
就是我们看到的加载器。您可以稍后将其删除。
const IconsImg = ({ img }) => {
const [loading, setLoding] = React.useState(true);
return <div >{loading && "Loading..."} <img alt={img} style={{display: loading ? "none" : "block"}} onLoad= {()=> setTimeout(()=> setLoding(false), 1000)} src = "https://images.unsplash.com/photo-1657664042206-1a98fa4d153d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHwxfHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=500&q=60"/></div>;
};
/* The below code is to have a working example here at Stack Overflow */
ReactDOM.render(
<IconsImg img= "car" />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
newImg
与icons[img]
是不同的对象。loading
设置时对于true
,浏览器这次为icons[img]
加载相同的src。
你可以试试这个:
如果loading
是false
,则首先为icons[img]
设置display:none
;
和:
<React.Fragment>
{loading || (
<Spinner>
)}
icons[img]
</React.Fragment>
然后:
useEffect(() => {
icons[img].onload = () => {
setLoading(true);
};
}, []);
或更好:
<img className={classes.imgStyle} alt="a" src={link} onload={() => setLoading(true)}/>