Created
February 8, 2018 22:05
-
-
Save bob-lee/78390bcd723ff953887f63f37a7dcd1f 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 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