Skip to content

Instantly share code, notes, and snippets.

@EQuimper
Created September 20, 2020 01:31
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save EQuimper/42e86abac2ee23143a1f6094ef960b87 to your computer and use it in GitHub Desktop.
Save EQuimper/42e86abac2ee23143a1f6094ef960b87 to your computer and use it in GitHub Desktop.
NextJS save scroll position between page for back handler
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);
};
}
}, []);
}
@DeeeeLAN
Copy link

This looks useful - do you have a quick example on how to utilize it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment