diff --git a/packages/gatsby-image/README.md b/packages/gatsby-image/README.md index 9ca5a9818fc92..c8b9448ad0bcc 100644 --- a/packages/gatsby-image/README.md +++ b/packages/gatsby-image/README.md @@ -276,6 +276,7 @@ prop. e.g. `` | `placeholderClassName` | `string` | A class that is passed to the placeholder `img` element | | `backgroundColor` | `string` / `bool` | Set a colored background placeholder. If true, uses "lightgray" for the color. You can also pass in any valid color string. | | `onLoad` | `func` | A callback that is called when the full-size image has loaded. | +| `onStartLoad` | `func` | A callback that is called when the full-size image starts loading, it gets the parameter { wasCached: boolean } provided. | | `onError` | `func` | A callback that is called when the image fails to load. | | `Tag` | `string` | Which HTML tag to use for wrapping elements. Defaults to `div`. | | `critical` | `bool` | Opt-out of lazy-loading behavior. Defaults to `false`. | diff --git a/packages/gatsby-image/index.d.ts b/packages/gatsby-image/index.d.ts index 7309346218bfe..c2252b03c162b 100644 --- a/packages/gatsby-image/index.d.ts +++ b/packages/gatsby-image/index.d.ts @@ -1,22 +1,48 @@ -import * as React from "react"; +import * as React from "react" + +interface FixedObject { + width: number + height: number + src: string + srcSet: string + base64?: string + tracedSVG?: string + srcWebp?: string + srcSetWebp?: string +} + +interface FluidObject { + aspectRatio: number + src: string + srcSet: string + sizes: string + base64: string + tracedSVG: string + srcWebp: string + srcSetWebp: string +} interface GatsbyImageProps { - resolutions?: object; - sizes?: object; - fixed?: object; - fluid?: object; - fadeIn?: boolean; - title?: string; - alt?: string; - className?: string | object; - critical?: boolean; - style?: object; - imgStyle?: object; - placeholderStyle?: object; - backgroundColor?: string | boolean; - onLoad?: (event: any) => void; - onError?: (event: any) => void; - Tag?: string; + resolutions?: FixedObject + sizes?: FluidObject + fixed?: FixedObject + fluid?: FluidObject + fadeIn?: boolean + title?: string + alt?: string + className?: string | object + critical?: boolean + style?: object + imgStyle?: object + placeholderStyle: object + backgroundColor?: string | boolean + onLoad?: () => void + onStartLoad?: (param: { wasCached: boolean }) => void + onError?: (event: any) => void + Tag?: string } -export default class GatsbyImage extends React.Component {} +export default class GatsbyImage extends React.Component< + GatsbyImageProps, + any +> {} diff --git a/packages/gatsby-image/src/index.js b/packages/gatsby-image/src/index.js index accd045662076..4686182ca244e 100644 --- a/packages/gatsby-image/src/index.js +++ b/packages/gatsby-image/src/index.js @@ -26,12 +26,17 @@ const inImageCache = props => { ? convertedProps.fluid.src : convertedProps.fixed.src - if (imageCache[src]) { - return true - } else { - imageCache[src] = true - return false - } + return imageCache[src] || false +} + +const activateCacheForImage = props => { + const convertedProps = convertProps(props) + // Find src + const src = convertedProps.fluid + ? convertedProps.fluid.src + : convertedProps.fixed.src + + imageCache[src] = true } let io @@ -172,6 +177,9 @@ class Image extends React.Component { } componentDidMount() { + if (this.state.isVisible && typeof this.props.onStartLoad === `function`) { + this.props.onStartLoad({ wasCached: inImageCache(this.props) }) + } if (this.props.critical) { const img = this.imageRef.current if (img && img.complete) { @@ -183,12 +191,21 @@ class Image extends React.Component { handleRef(ref) { if (this.state.IOSupported && ref) { listenToIntersections(ref, () => { - this.setState({ isVisible: true }) + if ( + !this.state.isVisible && + typeof this.props.onStartLoad === `function` + ) { + this.props.onStartLoad({ wasCached: inImageCache(this.props) }) + } + + this.setState({ isVisible: true, imgLoaded: false }) }) } } handleImageLoaded() { + activateCacheForImage(this.props) + this.setState({ imgLoaded: true }) if (this.state.seenBefore) { this.setState({ fadeIn: false }) @@ -462,6 +479,7 @@ Image.propTypes = { backgroundColor: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), onLoad: PropTypes.func, onError: PropTypes.func, + onStartLoad: PropTypes.func, Tag: PropTypes.string, }