-
Notifications
You must be signed in to change notification settings - Fork 502
Fix React scroll restoration on popState #2357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Fix React scroll restoration on popState #2357
Conversation
Thanks for this! Can confirm that this fixes it. I'll add a test and check if we need this on the other packages as well. |
Hmm, I can't seem to break it in the test app, just in the playground, so I have to dig a little bit deeper 🤔 |
Not sure of this helps but it’s broken when the page you’re navigating back from a shorter page to a longer page. Suppose page A is 1000px high and page B is 500px: This is what should happen:
This is what now incorrectly happens due to an issue in Inertia:
In my PR I wrap the scroll in requestAnimationFrame. In practice this delays the scroll until the next React render, when page A is back on screen. |
I think the test app is just too simple for this problem to appear 😅 But I can reproduce it if I deliberately make the I'll add a fix for that and also check SSR compatibility, probably calling |
I fiddled around some more and it could be possible that the delay of public static observeWindowResize(callback: () => void): VoidFunction {
const observer = new ResizeObserver(callback)
observer.observe(document.documentElement)
return () => observer.disconnect()
}
public static restoreDocument(): void {
if (typeof window === 'undefined') {
return
}
const scrollPosition = history.getDocumentScrollPosition()
const scrollToPosition = () => window.scrollTo(scrollPosition.left, scrollPosition.top)
// The newest page may not have been rendered yet, so we need to wait for the document to resize
// before scrolling to the saved position.
if (scrollPosition.top > document.documentElement.scrollHeight - window.innerHeight) {
const stopObserving = this.observeWindowResize(() => {
// todo: check height again...
scrollToPosition()
stopObserving()
})
// Observe for 100ms to allow the document to resize
setTimeout(stopObserving, 100)
return
}
scrollToPosition()
} |
Using
@inertiajs/react
, the scroll position isn't being restored becauseScroll.restore
is called before the new page is rendered. Wrapping it inrequestAnimationFrame
solves the issue, but I'm not sure if this is okay to have for the other adapters.