Issue
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 render 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, but 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>
)}
Solution
Issue
The problem with your last attempt is that you are starting with loading
showing the Spinner
, and you are trying to switch the state after the image is loaded, except that will never be the case, because the image is not mounted in the DOM.
Creating icons
is not equivalent to creating img
until it's added in the return
and mounted into the DOM. And I think it's loading twice cause at some point you added the two of them in the DOM either directly or after loading
changes.
Solution
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. That setTimeout
is so we see the loader. You can remove it later.
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>
Answered By - yousoumar
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.