This is a tricky issue and may not be easy to solve.
The issue is, for our current system, the images / photos are very big, such as 5MB or 6MB each, and uploaded by different teams every few days. Even though we can ask the backend team to have a system to convert them into thumbnail and smaller images later, such as 50kb or 150kb, it may still be a few months away and is beyond our control. (Another point is, when we let the user preview these photos in a modal, we may want to give them the full size image instead of a compressed one).
If we have vanilla JavaScript to load a second image, such as in an image preview modal on the webpage, when the user clicks on "Toggle" to see the next image (and Toggle again to see the next image), there are two issues:
the title and image mismatch with each other
the user cannot know that the image is being loaded. It is as if there is no reaction after clicking
The code is:
document
.querySelector("#toggle-button")
.addEventListener("click", () => {
toggle = !toggle;
filename = `${toggle ? "beach.jpg" : "mountain.jpg"}?${Date.now()}`;
elMsg.innerHTML = `<span>Title is ${
toggle ? "Beach" : "Mountain and Lake"
}</span>`;
elImage.src = filename;
});
and you can try the code here:
https://codesandbox.io/s/silly-haze-4uonqv?file=/index.html
To make the effect more obvious, please go to DevTool on Google Chrome, and then Network Tab, and change the "No Throttling" to "Slow 3G" speed.
Then you will see issue #1 and issue #2 mentioned above.
Note that here, I am using a Date.now()
to attach to the filename, so that the image URL is:
so as to bust the cache, for demo purpose to show the two issues.
It is the same if I use React, with the code:
function App() {
const [toggle, setToggle] = useState(true);
const imageFilename = `${
toggle ? "beach.jpg" : "mountain.jpg"
}?${Date.now()}`;
return (
<div className="App">
<div id="msg">
<span>toggle is {JSON.stringify(toggle)}</span>
<span>imageFilename is {imageFilename}</span>
<span>Title is {toggle ? "Beach" : "Mountain and Lake"}</span>
<button onClick={() => setToggle((f) => !f)}>Toggle</button>
</div>
<img src={imageFilename} alt="a big file" />
</div>
);
}
You can try it here:
https://codesandbox.io/s/floral-resonance-elouv7
Image 2 (mountain.jpg) is about 1.5MB, and the issue is more profound if the file is like 5MB or 6MB.
So what is a good way to handle this? If possible, I'd hope not to use complicated methods, such as using a spinner and use a two step method perhaps to first show a blank image placeholder, and then set the src
to the new one... because it is such an overkill for the purpose of just showing an image.
If it is Vanilla JavaScript, I did think of one quick method, which is to replace the whole <img />
each time:
elImageContainer.innerHTML = `<img src="${filename}" />`;
You can try it at
https://codesandbox.io/s/objective-bhabha-imdipn
But I don't think it can be done in React, which is what the project is using, because I think the new virtual DOM is created and is diff'ed with the previous virtual DOM, and there is no way to tell whether it is a new <img />
element like in the Vanilla JavaScript case.
Is there a good solution to this?