Created
April 17, 2020 11:21
-
-
Save beygi/28d7b286647248b1e7450cc228a8c053 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
import { useEffect } from 'react' | |
let domObserver: MutationObserver | null = null | |
let elementId: string = '' | |
const handleScroll = () => { | |
// user scoll event, we should cancel everything | |
cleanUpObserver() | |
elementId = '' | |
window.removeEventListener('scroll', handleScroll) | |
} | |
const cleanUpObserver = () => { | |
if (domObserver !== null) domObserver.disconnect() | |
} | |
const findElementAndScroll: (smooth?: boolean) => boolean = (smooth) => { | |
if (elementId !== '') { | |
const element = document.getElementById(elementId) | |
if (element) { | |
// remove scroll event listener because it's not user scroll | |
window.removeEventListener('scroll', handleScroll) | |
if (smooth) { | |
element.scrollIntoView({ behavior: 'smooth' }) | |
} else { | |
element.scrollIntoView() | |
} | |
// listen to scroll event again after scrolling to element | |
setTimeout(() => { | |
window.addEventListener('scroll', handleScroll) | |
}, 1000) | |
return true | |
} | |
return false | |
} | |
return false | |
} | |
const getElementAndScroll: MutationCallback = () => { | |
if (findElementAndScroll(true)) { | |
cleanUpObserver() | |
} | |
} | |
const setDomObserver = () => { | |
if (!domObserver) { | |
domObserver = new MutationObserver(getElementAndScroll) | |
} | |
domObserver.observe(document, { | |
attributes: true, | |
childList: true, | |
subtree: true, | |
}) | |
} | |
export default function useHashLink() { | |
const { hash, pathname } = window.location | |
const height = document.body.scrollHeight | |
useEffect(() => { | |
if (hash && elementId !== '') { | |
findElementAndScroll() | |
} | |
}, [hash, height]) | |
useEffect(() => { | |
// disconnect dom observer if exist | |
cleanUpObserver() | |
if (hash) { | |
elementId = hash.substring(1) | |
findElementAndScroll(true) | |
setDomObserver() | |
} | |
}, [hash, pathname]) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment