Skip to content

Commit

Permalink
fix(utils): subscribe method of createJSONStorage should only run in …
Browse files Browse the repository at this point in the history
…the client (#2585)

* fix: prevent calling storage subscribe unless in client

* test: add test for getStringStorage method from createJSONStorage to not be called in server

* use try-catch

* Revert "test: add test for getStringStorage method from createJSONStorage to not be called in server"

This reverts commit 71d2fa0.

* test: checking localStorage/sessionStorage access with createJSONStorage in server

* test: improve checking localStorage/sessionStorage access with createJSONStorage in server

* test: use defineProperty for checking localStorage/sessionStorage access with createJSONStorage in server

* fix: ts error in new test

* improve detecting browser storage access in client

* Update src/vanilla/utils/atomWithStorage.ts

* patch console.warn for atomWithStorage (in non-browser environment) test

---------

Co-authored-by: daishi <daishi@axlight.com>
Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 3, 2024
1 parent b236667 commit 48df663
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 4 deletions.
13 changes: 10 additions & 3 deletions src/vanilla/utils/atomWithStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,22 @@ export function createJSONStorage<Value>(
callback(newValue)
})

let subscriber = getStringStorage()?.subscribe
let subscriber: StringSubscribe | undefined
try {
subscriber = getStringStorage()?.subscribe
} catch {
// ignore
}
if (
!subscriber &&
typeof window !== 'undefined' &&
typeof window.addEventListener === 'function' &&
window.Storage &&
getStringStorage() instanceof window.Storage
window.Storage
) {
subscriber = (key, callback) => {
if (!(getStringStorage() instanceof window.Storage)) {
return () => {}
}
const storageEventCallback = (e: StorageEvent) => {
if (e.storageArea === getStringStorage() && e.key === key) {
callback(e.newValue)
Expand Down
44 changes: 43 additions & 1 deletion tests/react/vanilla-utils/atomWithStorage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -354,20 +354,62 @@ describe('atomWithStorage (in non-browser environment)', () => {
}

const addEventListener = window.addEventListener
const localStorage = window.localStorage
const sessionStorage = window.sessionStorage
const consoleWarn = window.console.warn

beforeAll(() => {
;(window as any).addEventListener = undefined
// patch console.warn to prevent logging along test results
Object.defineProperty(window.console, 'warn', {
value: () => {},
})
Object.defineProperties(window, {
localStorage: {
get() {
throw new Error('localStorage is not available.')
},
},
sessionStorage: {
get() {
throw new Error('sessionStorage is not available.')
},
},
})
})

afterAll(() => {
window.addEventListener = addEventListener
Object.defineProperty(window.console, 'warn', {
value: consoleWarn,
})
Object.defineProperties(window, {
localStorage: {
get() {
return localStorage
},
},
sessionStorage: {
get() {
return sessionStorage
},
},
})
})

it('createJSONStorage with undefined window.addEventListener', async () => {
const storage = createJSONStorage(() => asyncDummyStorage)

expect(storage.subscribe).toBeUndefined()
})

it('createJSONStorage with localStorage', async () => {
expect(() => createJSONStorage()).not.toThrow()
expect(() => createJSONStorage(() => window.localStorage)).not.toThrow()
})

it('createJSONStorage with sessionStorage', async () => {
expect(() => createJSONStorage(() => window.sessionStorage)).not.toThrow()
})
})

describe('atomWithStorage (with browser storage)', () => {
Expand Down

0 comments on commit 48df663

Please sign in to comment.