Skip to content

Instantly share code, notes, and snippets.

@bob-lee
Created February 8, 2018 22:05
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 bob-lee/78390bcd723ff953887f63f37a7dcd1f to your computer and use it in GitHub Desktop.
Save bob-lee/78390bcd723ff953887f63f37a7dcd1f to your computer and use it in GitHub Desktop.
import React from 'react';
import getUrls from './api'
const INTERSECT_PAGESIZE = 2;
export default class Observer extends React.Component {
state = { list: [] }
intersectionRatio = null; // 1: fully shown, 0.5: half shown, ..
elementToObserve = null; // img tag being obseved
_indexToObserve = null; // index of img tag being obseved
intersectionObserver = null; // instance of observer
constructor(props) {
super(props)
try {
this.intersectionObserver = typeof window !== 'undefined' && new IntersectionObserver(entries => {
const entry = entries[0]; // observe one element
const currentRatio = this.intersectionRatio;
const newRatio = entry.intersectionRatio;
const boundingClientRect = entry.boundingClientRect;
const scrollingDown = currentRatio !== undefined && newRatio < currentRatio &&
boundingClientRect.bottom < boundingClientRect.height;
this.intersectionRatio = newRatio;
if (scrollingDown) {
// it's scrolling down and observed image started to hide.
// so unobserve it and start loading next images.
const i = this.indexToObserve + INTERSECT_PAGESIZE;
this.unobserve();
this.indexToObserve = i; // set next index and load two more images
}
}, { threshold: [0, 0.25, 0.5, 0.75, 1] });
} catch (e) {
console.error('failed to create IntersectionObserver:', e);
}
}
get indexToObserve() {
return this._indexToObserve
}
set indexToObserve(value) {
const len = this.state.list.length;
const newList = [...this.state.list]
if (this._indexToObserve &&
(!value || value <= this._indexToObserve || value >= len)) {
return
}
this._indexToObserve = value;
// load more images
let countToLoad = 0
for (let i = 0; i < INTERSECT_PAGESIZE; i++) {
const index = this._indexToObserve + i;
if (index === len) {
break // reached page end
}
newList[index].toLoad = true
countToLoad++
}
if (countToLoad) {
this.setState({ list: newList })
}
}
getUrls(path) {
if (window.SERVER_DATA) {
this.itemsWithToLoad(window.SERVER_DATA)
window.SERVER_DATA = null
} else {
return getUrls(path).then(this.itemsWithToLoad)
}
}
itemsWithToLoad = (items) => {
const itemsWithToLoad = items.map((item, index) => (
{ toLoad: index < 2, ...item }
))
this._indexToObserve = 0
this.setState({ list: itemsWithToLoad })
}
componentWillUnmount() {
this.unobserve()
}
componentWillReceiveProps(nextProps) {
const path = this.props.match.params.name
const nextPath = nextProps.match.params.name
if (path !== nextPath) {
this.unobserve()
this.getUrls(nextPath)
}
}
componentDidMount() {
const path = this.props.match.params.name
this.getUrls(path)
}
observe = me => {
if (!me || !me.element || me.index === undefined) {
return;
}
if (me.index === this.indexToObserve) {
this.elementToObserve = me.element;
this.intersectionObserver.observe(me.element);
}
}
unobserve = () => { // unobserve current element
if (this.elementToObserve) {
this.intersectionObserver.unobserve(this.elementToObserve);
this.intersectionRatio = undefined;
}
}
render() {
return (
<div />
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment