Skip to content

Instantly share code, notes, and snippets.

@heggemsnes
Created March 30, 2021 08:02
Show Gist options
  • Save heggemsnes/daf6872d76b61bc83f2fa92082ffc22b to your computer and use it in GitHub Desktop.
Save heggemsnes/daf6872d76b61bc83f2fa92082ffc22b to your computer and use it in GitHub Desktop.
import React, { useState, useEffect, useRef } from 'react'
import { urlFor } from '../lib/api'
import useWindowDimensions from '../hooks/useWindowDimensions'
/* TODO: Add fallback image */
function LazyImage({
className,
image,
desktopSizePercent = 100,
fill = false,
aspectRatio,
}) {
const [loaded, setLoaded] = useState(false)
const imgRef = useRef()
const { height, width } = useWindowDimensions()
const [isMobile, setIsMobile] = useState(false)
const size = isMobile ? 1 : desktopSizePercent / 100
const lqip = image.metadata.lqip
const finalAspect = aspectRatio ?? image.metadata.dimensions.aspectRatio
const alt = image.alt
const screenSizes = [1920, 1600, 1366, 1024, 768, 640]
let srcSet = ''
const srcBase = urlFor(image.url)
.width(640 * size)
.auto('format')
.url()
screenSizes.forEach((eSize) => {
const url = urlFor(image.url)
.width(eSize * size)
.auto('format')
.url()
srcSet += `${url} ${eSize}w,`
})
useEffect(() => {
if (imgRef.current && imgRef.current.complete) {
setLoaded(true)
}
if (width < 768) setIsMobile(true)
}, [])
return (
<figure className={`${fill && 'h-full'}`}>
<div
className={`${
className ?? 'wrapper relative overflow-hidden w-full'
} ${fill && 'h-full'}`}
>
<div style={{ paddingBottom: `${100 / finalAspect}%` }} />
<img
className="absolute h-full w-full inset-0 object-cover object-center"
src={lqip}
aria-hidden="true"
alt={image?.altText && image.altText}
aria-label="Bilde laster"
/>
<img
loading="lazy"
src={srcBase}
srcSet={srcSet}
aria-label={image.title}
alt={image?.altText && image.altText}
ref={imgRef}
onLoad={() => setLoaded(true)}
className={`absolute h-full w-full inset-0 object-cover object-center transition-opacity duration-700 ${
loaded ? 'opacity-100' : 'opacity-0'
}`}
/>
</div>
{image.caption && (
<figcaption className="primary">{image.caption}</figcaption>
)}
</figure>
)
}
export default LazyImage
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment