Created
September 20, 2020 01:31
-
-
Save EQuimper/42e86abac2ee23143a1f6094ef960b87 to your computer and use it in GitHub Desktop.
NextJS save scroll position between page for back handler
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 Router, { NextRouter } from 'next/router'; | |
// Save the scroll position for the given url | |
function saveScrollPosition( | |
url: string, | |
element: HTMLElement, | |
savePosition: (url: string, pos: number) => void | |
) { | |
savePosition(url, element.scrollTop); | |
} | |
// Restore the scroll position for the given url is possible | |
function restoreScrollPosition( | |
url: string, | |
element: HTMLElement, | |
positions: React.RefObject<{ [key: string]: number }> | |
) { | |
const position = positions.current[url]; | |
if (position) { | |
element.scrollTo({ top: position }); | |
} | |
} | |
export default function useScrollRestoration(router: NextRouter) { | |
const positions = React.useRef<{ [key: string]: number }>({}); | |
console.log('positions', positions); | |
const updatePosition = (url: string, pos: number) => { | |
positions.current = { | |
...positions.current, | |
[url]: pos, | |
}; | |
}; | |
React.useEffect(() => { | |
if ('scrollRestoration' in window.history) { | |
let shouldScrollRestore = false; | |
window.history.scrollRestoration = 'manual'; | |
const element = document.getElementById('content'); | |
const onBeforeUnload = (event) => { | |
saveScrollPosition(router.asPath, element, updatePosition); | |
delete event['returnValue']; | |
}; | |
const onRouteChangeStart = () => { | |
saveScrollPosition(router.asPath, element, updatePosition); | |
}; | |
const onRouteChangeComplete = (url: string) => { | |
if (shouldScrollRestore) { | |
shouldScrollRestore = false; | |
restoreScrollPosition(url, element, positions); | |
} | |
}; | |
window.addEventListener('beforeunload', onBeforeUnload); | |
Router.events.on('routeChangeStart', onRouteChangeStart); | |
Router.events.on('routeChangeComplete', onRouteChangeComplete); | |
Router.beforePopState(() => { | |
shouldScrollRestore = true; | |
return true; | |
}); | |
return () => { | |
window.removeEventListener('beforeunload', onBeforeUnload); | |
Router.events.off('routeChangeStart', onRouteChangeStart); | |
Router.events.off('routeChangeComplete', onRouteChangeComplete); | |
Router.beforePopState(() => true); | |
}; | |
} | |
}, []); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This looks useful - do you have a quick example on how to utilize it?