Skip to content

Commit e18b333

Browse files
fix: properly handle sessionStorage not being available for scroll restoration (#4186)
1 parent fa871a0 commit e18b333

File tree

3 files changed

+46
-29
lines changed

3 files changed

+46
-29
lines changed

packages/react-router/src/ScrollRestoration.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,6 @@ export function useElementScrollRestoration(
6464
}
6565

6666
const restoreKey = getKey(router.latestLocation)
67-
const byKey = scrollRestorationCache.state[restoreKey]
67+
const byKey = scrollRestorationCache?.state[restoreKey]
6868
return byKey?.[elementSelector]
6969
}

packages/router-core/src/scroll-restoration.ts

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,22 @@ export type ScrollRestorationOptions = {
1818
scrollBehavior?: ScrollToOptions['behavior']
1919
}
2020

21+
function getSafeSessionStorage() {
22+
try {
23+
if (
24+
typeof window !== 'undefined' &&
25+
typeof window.sessionStorage === 'object'
26+
) {
27+
return window.sessionStorage
28+
}
29+
} catch {
30+
return undefined
31+
}
32+
return undefined
33+
}
34+
2135
export const storageKey = 'tsr-scroll-restoration-v1_3'
22-
let sessionsStorage = false
23-
try {
24-
sessionsStorage =
25-
typeof window !== 'undefined' && typeof window.sessionStorage === 'object'
26-
} catch {}
36+
2737
const throttle = (fn: (...args: Array<any>) => void, wait: number) => {
2838
let timeout: any
2939
return (...args: Array<any>) => {
@@ -35,28 +45,32 @@ const throttle = (fn: (...args: Array<any>) => void, wait: number) => {
3545
}
3646
}
3747
}
38-
export const scrollRestorationCache: ScrollRestorationCache = sessionsStorage
39-
? (() => {
40-
const state: ScrollRestorationByKey =
41-
JSON.parse(window.sessionStorage.getItem(storageKey) || 'null') || {}
42-
43-
return {
44-
state,
45-
// This setter is simply to make sure that we set the sessionStorage right
46-
// after the state is updated. It doesn't necessarily need to be a functional
47-
// update.
48-
set: (updater) => (
49-
(scrollRestorationCache.state =
50-
functionalUpdate(updater, scrollRestorationCache.state) ||
51-
scrollRestorationCache.state),
52-
window.sessionStorage.setItem(
53-
storageKey,
54-
JSON.stringify(scrollRestorationCache.state),
55-
)
56-
),
57-
}
58-
})()
59-
: (undefined as any)
48+
49+
function createScrollRestorationCache(): ScrollRestorationCache | undefined {
50+
const safeSessionStorage = getSafeSessionStorage()
51+
if (!safeSessionStorage) {
52+
return undefined
53+
}
54+
55+
const persistedState = safeSessionStorage.getItem(storageKey)
56+
let state: ScrollRestorationByKey = persistedState
57+
? JSON.parse(persistedState)
58+
: {}
59+
60+
return {
61+
state,
62+
// This setter is simply to make sure that we set the sessionStorage right
63+
// after the state is updated. It doesn't necessarily need to be a functional
64+
// update.
65+
set: (updater) => (
66+
(state = functionalUpdate(updater, state) || state),
67+
safeSessionStorage.setItem(storageKey, JSON.stringify(state))
68+
),
69+
}
70+
}
71+
72+
export const scrollRestorationCache = createScrollRestorationCache()
73+
6074
/**
6175
* The default `getKey` function for `useScrollRestoration`.
6276
* It returns the `key` from the location state or the `href` of the location.
@@ -176,6 +190,9 @@ export function restoreScroll(
176190
}
177191

178192
export function setupScrollRestoration(router: AnyRouter, force?: boolean) {
193+
if (scrollRestorationCache === undefined) {
194+
return
195+
}
179196
const shouldScrollRestoration =
180197
force ?? router.options.scrollRestoration ?? false
181198

packages/solid-router/src/ScrollRestoration.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,6 @@ export function useElementScrollRestoration(
6464
}
6565

6666
const restoreKey = getKey(router.latestLocation)
67-
const byKey = scrollRestorationCache.state[restoreKey]
67+
const byKey = scrollRestorationCache?.state[restoreKey]
6868
return byKey?.[elementSelector]
6969
}

0 commit comments

Comments
 (0)