Skip to content

Instantly share code, notes, and snippets.

@tsh-code
Created October 29, 2019 13:17
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 tsh-code/16679814836cb02324e220f505714d10 to your computer and use it in GitHub Desktop.
Save tsh-code/16679814836cb02324e220f505714d10 to your computer and use it in GitHub Desktop.
import React, { Component, ReactNode, ImgHTMLAttributes } from 'react';
import { findDOMNode } from 'react-dom';
interface LazyImageComponentPropsInterface extends ImgHTMLAttributes<HTMLImageElement> {
onChangeIntersection?: (isIntersecting: boolean) => void;
placeholder?: string;
}
interface LazyImageComponentStateInterface {
isLoadable: boolean;
}
export class LazyImage extends Component<LazyImageComponentPropsInterface, LazyImageComponentStateInterface> {
private readonly intersectionObserver: IntersectionObserver;
public state: LazyImageComponentStateInterface = {
isLoadable: false,
};
constructor(props: LazyImageComponentPropsInterface) {
super(props);
// Do not use it like this in production-quality code.
// Cache instances of IntersectionObserver
this.intersectionObserver = new IntersectionObserver(this.onCallbackIntersectionObserver, {
threshold: 0,
// Begin intersecting 25% of the viewport height before it appears to reduce chance of displaying
// unloaded content
rootMargin: '0px 0px 25% 0px',
});
}
public componentDidMount(): void {
this.intersectionObserver.observe(findDOMNode(this) as Element);
}
public componentWillUnmount(): void {
this.intersectionObserver.disconnect();
}
public render(): ReactNode {
const { onChangeIntersection, placeholder, ...restImgProps } = this.props;
const { isLoadable } = this.state;
return (
<img {...restImgProps} src={isLoadable ? this.props.src : placeholder}/>
);
}
private onCallbackIntersectionObserver = (entries: IntersectionObserverEntry[]) => {
const { onChangeIntersection } = this.props;
// Ignore additional entries since there's only one.
// Add the logic if you plan to handle multiple entries per intersection observer instance
// especially in production code.
const entry = entries[0];
if (onChangeIntersection) {
onChangeIntersection(entry.isIntersecting);
}
if (!this.state.isLoadable && entry.isIntersecting) {
this.setState({
isLoadable: true,
});
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment