Skip to content

Instantly share code, notes, and snippets.

@idris95
Last active December 3, 2020 15:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save idris95/a44f4f51a44ea37afdff3524457fd604 to your computer and use it in GitHub Desktop.
Save idris95/a44f4f51a44ea37afdff3524457fd604 to your computer and use it in GitHub Desktop.
Custom react lazy load image component with typescript
import React, { FC, useRef, useState, useEffect } from 'react';
import styled from 'styled-components';
const placeHolder =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkqAcAAIUAgUW0RjgAAAAASUVORK5CYII=';
const Image = styled.img`
display: block;
@keyframes loaded {
0% {
opacity: 0.1;
}
100% {
opacity: 1;
}
}
&.loaded:not(.has-error) {
animation: loaded 300ms ease-in-out;
}
&.has-error {
content: url(${placeHolder});
}
`;
type PropsType = {
src: string;
alt: string;
};
const Img: FC<PropsType> = ({ src, alt }) => {
const [imageSrc, setImageSrc] = useState(placeHolder);
const imageRef = useRef(null);
const onLoad = (event: any) => {
event.target.classList.add('loaded');
};
const onError = (event: any) => {
event.target.classList.add('has-error');
};
useEffect(() => {
let observer: any;
let didCancel = false;
const newImageRef: any = imageRef?.current;
if (newImageRef && newImageRef !== src) {
if (IntersectionObserver) {
observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (
!didCancel &&
(entry.intersectionRatio > 0 || entry.isIntersecting)
) {
setImageSrc(src);
observer.unobserve(newImageRef);
}
});
},
{
threshold: 0.01,
rootMargin: '75%',
}
);
observer.observe(newImageRef);
} else {
// Old browsers fallback
setImageSrc(src);
}
}
return () => {
didCancel = true;
// on component cleanup, we remove the listner
if (observer && observer.unobserve) {
observer.unobserve(newImageRef);
}
};
}, [src, imageSrc, imageRef]);
return (
<Image
ref={imageRef}
src={imageSrc}
alt={alt}
onLoad={onLoad}
onError={onError}
/>
);
};
export default Img;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment