-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
If gatsby-image already has an item in cache, don't show the placeholder #12254
Comments
By "in cache" is this referring to the browser cache for images or the lookup object/dict Also note the If ignoring the |
I have spent time looking into resolving this.
A) Prior browser cache check logic via PromisePreviously, I was doing a more thorough check of the browser cache via a promise that would wait about 10ms to check the browser cache(0ms for in-memory cache, but disk-cache on SSD with my system would require up to 10ms, on slower systems or disk access, that could be even longer making it less reliable: // A function outside of `Image` component
const isImageCached = (currentSrc) => {
return new Promise((resolve, reject) => {
// empty string if not in the browser cache
if (currentSrc.length > 0) {
const image = new window.Image();
image.src = currentSrc;
const checkBrowserCache = () => {
const isCached = image.complete
image.src = ""
resolve(isCached)
}
// Image should be loaded via browser cache within 10ms
setTimeout(checkBrowserCache, 10);
} else {
resolve(false)
}
})
}
// Within `handleRef()`:
const img = this.imageRef.current
isImageCached(img.currentSrc).then(isCached =>
this.setState({ imgCached: isCached })
) I have since removed the need for the Also depending how transition styles are managed, if a transition is already active, changing it's duration/delay has no effect iirc, you had to adjust the opacity value to trigger a new transition animation, so this was another benefit of keeping these two state updates together. B) Trust currentSrc value as a cache hitAFAIK, this can be simplified to just checking the length of Simplified(also now updates with this.setState({
imgLoaded: imageInCache,
imgCached: this.imageRef.current.currentSrc.length > 0
}) C) Chained/nested setState() callShould this 2nd setState() be used as the 2nd param for the 1st setState()? due to the async nature of setState(), it might be more reliable/consistent this way(it would then always be applied after the first state has been updated and rendered IIRC, vs potentially being batched and breaking like described above as a single state update(I haven't experienced such when doing the 2nd state update directly after).
this.setState(
{ isVisible: true },
() => this.setState({
imgLoaded: imageInCache,
imgCached: this.imageRef.current.currentSrc.length > 0
})
) Placeholder can briefly be seen, could use CSS Keyframes to avoid?You're likely to still see the placeholder graphic for a brief moment when it's delivered in the initial html payload(base64), until the JS kicks in.** Is that acceptable? ** If you want to avoid that as well, then I believe we need something like CSS Keyframe animation to initialize the placeholder opacity at 0, and fade-in after an initial delay(250-500ms for slow devices), in cached scenarios the JS should be able to cancel that keyframe animation from starting. imgCached boolean added to negate transition styles for browser cache hitsI introduce a If the developer wants the cached image to still have a fade-in effect, they'll need to add the additional style to override transitionDelay for placeholders, remove conditional, use 0.5s always
The 0.25 and 0.35 delays for these placeholders, perhaps they were intended for fade-in? Which won't work due to their opacity starting at 1 any how? A developer may want to override the placeholder transition styles for transparent images during loading as well, so that the placeholder is removed/replaced by the full image fading in ASAP. Presently, there is no control for the developer to do this with transition duration on image placeholderThis style has been with the component since it's arrival. The style was later moved, and someone observed that it was no longer applied to the base64 placeholder, made a PR and got it merged back. Thing is, with the transition delay and current behaviour, you're not actually going to see this placeholder do a transition(except on transparent images where it probably doesn't look nice). Is removing it ok? Styles for browser cache hits, avoiding transitionsconst imagePlaceholderStyle = {
opacity: this.state.imgLoaded ? 0 : 1,
transitionDelay: this.state.imgCached ? `0s` : `0.5s`,
...imgStyle,
...placeholderStyle,
}
const shouldDisplay = this.state.imgLoaded || this.state.fadeIn === false
const shouldFadeIn = this.state.fadeIn === true && !this.state.imgCached
const imageStyle = {
opacity: shouldDisplay ? 1 : 0,
transition: shouldFadeIn ? `opacity 0.5s` : `none`,
...imgStyle,
} With transition duration (and alternative to avoid assigning transition rules): const transitionStyle = {
transition: `opacity 0.5s`,
transitionDelay: `0.5s`
}
const imagePlaceholderStyle = {
opacity: this.state.imgLoaded ? 0 : 1,
...(!this.state.imgCached && transitionStyle),
...imgStyle,
...placeholderStyle,
} I'll go ahead and setup a PR. |
Hiya! This issue has gone quiet. Spooky quiet. 👻 We get a lot of issues, so we currently close issues after 30 days of inactivity. It’s been at least 20 days since the last update here. If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open! Thanks for being a part of the Gatsby community! 💪💜 |
I see the branch was already merged, but it seems like I'm still experiencing the described issue by @KyleAMathews. |
@devrnt Do you have an example/reproduction that demonstrates this? Or a link to an affected project online? Are you using any props like There's a possibility that the image config(props & feature support) for that logo is causing the browsers image cache check to not be performed. |
@polarathene Since I didn't figure out the problem I moved to use a svg. It was a strange behaviour. The 'problem' is the same as on this webpage: https://www.gatsbyjs.org/blog/2019-03-01-localization-with-gatsby-and-sanity/ Since everything was cached and available offline (in my case) I would think that that the blur should disappear, but it was reloading every time (like on the example) when changed from page. (home to contact etc.) When the problem was occuring I used a fixed |
@devrnt can you explain what action you're doing to reproduce the issue you're experiencing? In the gatsby blogpost link, what should I click/navigate? If you just navigate to another page in the header links, and click the browsers back button(or via mobile), you may briefly see the base64 placeholder, but you won't see the transition effect anymore. Just to clarify. Are you referring to the low quality base64 image as the blur effect? Or the actual CSS transition that fades it out over 0.5 sec? This feature does not have the ability to remove the base64 image until the JS for the react gatsby-image component can run. The HTML is sent with that base64 placeholder, so it will be present still on a refresh, even if your cache has the full image. The slower the device to process the JS (and for React to update the DOM after), the longer that placeholder will be visible. I proposed earlier in this issue, that it could be addressed with a CSS keyframe transition, but this cannot be done via inline styles afaik. It would allow you to not show the placeholder for a small duration to give React some time to kick in. Also, as you've not mentioned your project as being online, if this is something you're experiencing during development, please be aware that TL;DR: If the network tab does confirm the image is cached and you are experiencing a fade transition effect that occurs when there is no cache, then that is indeed a bug. Otherwise, it may briefly be visible. |
@polarathene Thanks for the extensive information. I've reproduced the issue: https://yvesdevrient.netlify.com/ As I can see in the network tab it says both the logo and banner are in |
@devrnt the url doesn't seem to be valid. I get "Not Found". |
@polarathene It's back online. |
@devrnt Yes I can see what you are referring to. That is the base64 placeholder flashing/"stuttering". Is it in the Layout component? Or are you placing the header in each page component? It looks like the logo is being unmounted and remounted each time for some reason. Whatever the cause, this behaviour is unrelated to this issue or the PR that addressed it. I would suggest reaching out via community support, such as the Discord server. If no one is able to assist you in identifying the cause of the issue, create a public github repo that demonstrates the behaviour and then raise a new issue here linking to it. In the meantime, you can use a graphql fragment that won't apply a base64 placeholder:
|
@polarathene Thank you very much! Edit: I saw that the parent component of my logo was rebuilding on changing page, that explains why it does rebuild. |
@devrnt |
You can see this happening on this blog post. Click to it and back several times. The blurred up base64 image is shown every time.
https://www.gatsbyjs.org/blog/2019-03-01-localization-with-gatsby-and-sanity/
The text was updated successfully, but these errors were encountered: