Created
August 26, 2021 13:39
-
-
Save stephanschubert/042b9d87e9541f205fcc5291653bac19 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
const Layout = () => { | |
const [ref, sticky] = useSticky(); | |
return ( | |
<div className={"layout"} ref={ref}> | |
<div | |
className={cx("sticky z-20 top-0", { | |
"shadow-md": sticky, | |
})} | |
> | |
<Header /> | |
</div> | |
... |
This file contains hidden or 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 { useRafState as useState } from "react-use"; | |
import { useEffect, useRef } from "react"; | |
/** | |
* Returns a ref, and a stateful value bound to the ref | |
* @returns [Any, Boolean] | |
*/ | |
const useSticky = () => { | |
const stickyRef = useRef(null); | |
const [sticky, setSticky] = useState(false); | |
useEffect(() => { | |
// Observe when ref enters or leaves sticky state | |
// rAF https://stackoverflow.com/questions/41740082/scroll-events-requestanimationframe-vs-requestidlecallback-vs-passive-event-lis | |
function observe() { | |
if (!stickyRef.current) { | |
setSticky(false); | |
return; | |
} | |
const refPageOffset = stickyRef.current.getBoundingClientRect().top; | |
const stickyOffset = parseInt(getComputedStyle(stickyRef.current).top); | |
const stickyActive = isNaN(stickyOffset) | |
? refPageOffset < 0 | |
: refPageOffset <= stickyOffset; | |
// console.log({ refPageOffset, stickyOffset, stickyActive, sticky }) | |
if (stickyActive && !sticky) setSticky(true); | |
else if (!stickyActive && sticky) setSticky(false); | |
} | |
const eventsToBind = [ | |
[document, "scroll"], | |
[window, "resize"], | |
[window, "orientationchange"], | |
]; | |
if (stickyRef.current) { | |
observe(); | |
// Bind events | |
eventsToBind.forEach(eventPair => { | |
eventPair[0].addEventListener(eventPair[1], observe); | |
}); | |
} | |
return () => { | |
eventsToBind.forEach(eventPair => { | |
eventPair[0].removeEventListener(eventPair[1], observe); | |
}); | |
}; | |
}, [stickyRef, sticky]); | |
return [stickyRef, sticky]; | |
}; | |
export default useSticky; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment