Skip to content

Commit

Permalink
persist scroll positions in sessionStorage
Browse files Browse the repository at this point in the history
  • Loading branch information
david-crespo committed Jun 5, 2023
1 parent ef04b9c commit dbf0416
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 7 deletions.
23 changes: 16 additions & 7 deletions app/hooks/use-scroll-restoration.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
import { useEffect, useRef } from 'react'
import { useEffect } from 'react'
import { useLocation, useNavigation } from 'react-router-dom'

function getScrollPosition(key: string) {
const pos = window.sessionStorage.getItem(key)
return pos && /^[0-9]+$/ ? parseInt(pos, 10) : 0
}

function setScrollPosition(key: string, pos: number) {
window.sessionStorage.setItem(key, pos.toString())
}

/**
* Given a ref to a scrolling container element, keep track of its scroll
* position before navigation and restore it on return (e.g., back/forward nav).
* Note that `location.key` is used as the cache key, not `location.pathname`,
* Note that `location.key` is used in the cache key, not `location.pathname`,
* so the same path navigated to at different points in the history stack will
* not share the same scroll position.
*/
export function useScrollRestoration(container: React.RefObject<HTMLElement>) {
const cache = useRef(new Map<string, number>())
const { key } = useLocation()
const key = `scroll-position-${useLocation().key}`
const { state } = useNavigation()
useEffect(() => {
if (state === 'loading') {
cache.current.set(key, container.current?.scrollTop ?? 0)
} else if (state === 'idle' && cache.current.has(key)) {
container.current?.scrollTo(0, cache.current.get(key)!)
const pos = container.current?.scrollTop ?? 0
setScrollPosition(key, pos)
} else if (state === 'idle') {
container.current?.scrollTo(0, getScrollPosition(key))
}
}, [key, state, container])
}
5 changes: 5 additions & 0 deletions app/test/e2e/scroll-restore.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ test('scroll restore', async ({ page }) => {
await page.getByRole('link', { name: 'Disks' }).click()
await expectScrollTop(page, 0)

// random reload in there because we use sessionStorage. note we are
// deliberately on the disks page here because there's a quirk in playwright
// that seems to reset to the disks page on reload
await page.reload()

// back to snapshots, scroll is restored
await page.goBack()
await expect(page).toHaveURL('/projects/mock-project/snapshots')
Expand Down

0 comments on commit dbf0416

Please sign in to comment.