I have the following logic that renders an image, the current flow is like the following if the state is false a spinner shows then when the image loads the spinner disappears , the core problem here is the state is re-rendering the component causing the image to load again I kind of ran out of options, on how to make an instant switch after the image loads. it is not a loop but rather the image reloads again even if it is already loaded due to the retender caused by setLoading(true); how to prevent this reloading from happening. the useEffect logic is just a simulator for how it might take to load the image buy my real image coms from the icons variable.
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>
)}
CodePudding user response:
newImg
is a different object from icons[img]
. When loading
set
to true
, browser loads same src this time for icons[img]
.
You can try this:
First set display:none
for icons[img]
if loading
is false
;
And:
<React.Fragment>
{loading || (
<Spinner>
)}
icons[img]
</React.Fragment>
Then:
useEffect(() => {
icons[img].onload = () => {
setLoading(true);
};
}, []);
or better:
<img className={classes.imgStyle} alt="a" src={link} onl oad={() => setLoading(true)}/>
CodePudding user response:
You can simplify your component as below. Notice I removed icons
and setting alt
attribute (the one difference between the two) while creating the image.
const IconsImg = ({ img }) => {
const [loading, setLoding] = React.useState(true);
return <div >{loading && "Loading..."} <img alt={img} style={{display: loading ? "none" : "block"}} onl oad= {()=> setTimeout(()=> setLoding(false), 1000)} src = "https://images.unsplash.com/photo-1657664042206-1a98fa4d153d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHwxfHx8ZW58MHx8fHw=&auto=format&fit=crop&w=500&q=60"/></div>;
};
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>
That setTimeout
is so we see the loader. You can remove it later.