Created
November 8, 2019 22:42
-
-
Save cwgw/0646bedaa7bc326999aa889c28cfca51 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 throttle from 'lodash/throttle'; | |
let io; | |
let isInstantiated = false; | |
const listeners = new WeakMap(); | |
const animationQueue = new Set([]); | |
const rootMargin = 100; | |
let pageYOffset = null; | |
const animate = throttle( | |
() => { | |
if (!animationQueue.size) return; | |
pageYOffset = window.pageYOffset; | |
animationQueue.forEach(callAnimation); | |
}, | |
1000 / 30, | |
{ leading: true, trailing: true } | |
); | |
function useParallax (cb) { | |
if (typeof window === 'undefined') return null; | |
if (typeof window.IntersectionObserver !== 'function') return null; | |
const [ref, setRef] = React.useState(null); | |
React.useLayoutEffect(() => { | |
if (ref) { | |
listenToIntersections(ref, cb); | |
} | |
}, [ref]); | |
return setRef; | |
} | |
function getIO() { | |
if ( | |
typeof io === `undefined` && | |
typeof window !== `undefined` && | |
window.IntersectionObserver | |
) { | |
io = new window.IntersectionObserver( | |
entries => { | |
entries.forEach(entry => { | |
if (listeners.has(entry.target)) { | |
const { cb } = listeners.get(entry.target); | |
// Edge doesn't currently support isIntersecting, so also test for an intersectionRatio > 0 | |
if (entry.isIntersecting || entry.intersectionRatio > 0) { | |
listeners.set(entry.target, { | |
cb, | |
entry: { | |
range: | |
entry.rootBounds.height + entry.boundingClientRect.height, | |
center: | |
pageYOffset + | |
entry.boundingClientRect.top + | |
rootMargin - | |
entry.rootBounds.height, | |
}, | |
}); | |
animationQueue.add(entry.target); | |
animate(); | |
} else { | |
animationQueue.delete(entry.target); | |
} | |
} | |
}); | |
}, | |
{ rootMargin: `${rootMargin}px`, threshold: 0 } | |
); | |
} | |
return io; | |
} | |
function listenToIntersections (el, cb) { | |
const observer = getIO(); | |
if (observer) { | |
if (!isInstantiated) { | |
window.addEventListener('scroll', animate); | |
isInstantiated = true; | |
} | |
observer.observe(el); | |
listeners.set(el, { cb, entry: {} }); | |
} | |
return () => { | |
observer.unobserve(el); | |
listeners.delete(el); | |
if (!listeners.size) { | |
window.removeEventListener('scroll', animate); | |
isInstantiated = false; | |
} | |
}; | |
} | |
function callAnimation (el) { | |
const { cb, entry } = listeners.get(el); | |
const y = (pageYOffset - entry.center) / entry.range; | |
cb(y, { ref: entry.target }); | |
} | |
export default useParallax; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment