Created
October 29, 2019 13:17
-
-
Save tsh-code/16679814836cb02324e220f505714d10 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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