Last active
August 2, 2024 06:25
-
-
Save GusRuss89/df05ea25310043fc38a5e2ba3cb0c016 to your computer and use it in GitHub Desktop.
Nextjs - keep state and scroll position between page transitions. Described in detail here - https://medium.com/@angus.russell89/next-js-keep-page-components-mounted-between-page-transitions-and-maintain-scroll-position-205b34539a26
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 React, { useRef, useEffect, memo } from 'react' | |
import { useRouter } from 'next/router' | |
const ROUTES_TO_RETAIN = ['/dashboard', '/top', '/recent', 'my-posts'] | |
const App = ({ Component, pageProps }) => { | |
const router = useRouter() | |
const retainedComponents = useRef({}) | |
const isRetainableRoute = ROUTES_TO_RETAIN.includes(router.asPath) | |
// Add Component to retainedComponents if we haven't got it already | |
if (isRetainableRoute && !retainedComponents.current[router.asPath]) { | |
const MemoComponent = memo(Component) | |
retainedComponents.current[router.asPath] = { | |
component: <MemoComponent {...pageProps} />, | |
scrollPos: 0 | |
} | |
} | |
// Save the scroll position of current page before leaving | |
const handleRouteChangeStart = url => { | |
if (isRetainableRoute) { | |
retainedComponents.current[router.asPath].scrollPos = window.scrollY | |
} | |
} | |
// Save scroll position - requires an up-to-date router.asPath | |
useEffect(() => { | |
router.events.on('routeChangeStart', handleRouteChangeStart) | |
return () => { | |
router.events.off('routeChangeStart', handleRouteChangeStart) | |
} | |
}, [router.asPath]) | |
// Scroll to the saved position when we load a retained component | |
useEffect(() => { | |
if (isRetainableRoute) { | |
window.scrollTo(0, retainedComponents.current[router.asPath].scrollPos) | |
} | |
}, [Component, pageProps]) | |
return ( | |
<div> | |
<div style={{ display: isRetainableRoute ? 'block' : 'none' }}> | |
{Object.entries(retainedComponents.current).map(([path, c]) => ( | |
<div | |
key={path} | |
style={{ display: router.asPath === path ? 'block' : 'none' }} | |
> | |
{c.component} | |
</div> | |
))} | |
</div> | |
{!isRetainableRoute && <Component {...pageProps} />} | |
</div> | |
) | |
} | |
export default App |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@nandorojo I'm not familiar with
ScrollView
but surely it has some way to get and set the scroll position? If so it should be exactly the same but with those methods instead ofwindow.scrollY
andwindow.scrollTo()
.