Skip to content

Commit

Permalink
fix(useStorage): emit a custom event to support custom storage areas (#…
Browse files Browse the repository at this point in the history
…2630)

Co-authored-by: Jelf <353742991@qq.com>
  • Loading branch information
43081j and okxiaoliang4 committed Feb 14, 2023
1 parent 8151120 commit c6185bf
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 9 deletions.
25 changes: 24 additions & 1 deletion packages/core/useStorage/index.test.ts
@@ -1,7 +1,7 @@
import { debounceFilter, promiseTimeout } from '@vueuse/shared'
import { isVue3, ref } from 'vue-demi'
import { nextTwoTick, useSetup } from '../../.test'
import { StorageSerializers, useStorage } from '.'
import { StorageSerializers, customStorageEventName, useStorage } from '.'

const KEY = 'custom-key'

Expand Down Expand Up @@ -429,6 +429,29 @@ describe('useStorage', () => {
expect(data.value).toBe(1)
})

it('emits custom storage events on change', async () => {
const eventFn = vi.fn()
const data0 = useStorage(KEY, 0, storage)
const data1 = useStorage(KEY, 0, storage)
expect(data0.value).toBe(0)
expect(data1.value).toBe(0)

window.addEventListener(customStorageEventName, eventFn, { once: true })

data0.value = 1
await nextTwoTick()

expect(data0.value).toBe(1)
expect(data1.value).toBe(1)
expect(eventFn).toHaveBeenCalled()
const call = eventFn.mock.calls[0] as [CustomEvent]

expect(call[0].detail.storageArea).toEqual(storage)
expect(call[0].detail.key).toEqual(KEY)
expect(call[0].detail.oldValue).toEqual('0')
expect(call[0].detail.newValue).toEqual('1')
})

it('handle error', () => {
expect(useStorage(KEY, 0).value).toBe(0)
expect(console.error).toHaveBeenCalledWith(new Error('getDefaultStorage error'))
Expand Down
35 changes: 27 additions & 8 deletions packages/core/useStorage/index.ts
Expand Up @@ -53,6 +53,15 @@ export const StorageSerializers: Record<'boolean' | 'object' | 'number' | 'any'
},
}

export const customStorageEventName = 'vueuse-storage'

export interface StorageEventLike {
storageArea: StorageLike | null
key: StorageEvent['key']
oldValue: StorageEvent['oldValue']
newValue: StorageEvent['newValue']
}

export interface UseStorageOptions<T> extends ConfigurableEventFilter, ConfigurableWindow, ConfigurableFlush {
/**
* Watch for deep changes
Expand Down Expand Up @@ -160,8 +169,10 @@ export function useStorage<T extends(string | number | boolean | object | null)>
{ flush, deep, eventFilter },
)

if (window && listenToStorageChanges)
if (window && listenToStorageChanges) {
useEventListener(window, 'storage', update)
useEventListener(window, customStorageEventName, updateFromCustomEvent)
}

update()

Expand All @@ -179,12 +190,16 @@ export function useStorage<T extends(string | number | boolean | object | null)>
storage!.setItem(key, serialized)

// send custom event to communicate within same page
// importantly this should _not_ be a StorageEvent since those cannot
// be constructed with a non-built-in storage area
if (window) {
window?.dispatchEvent(new StorageEvent('storage', {
key,
oldValue,
newValue: serialized,
storageArea: storage as any,
window.dispatchEvent(new CustomEvent<StorageEventLike>(customStorageEventName, {
detail: {
key,
oldValue,
newValue: serialized,
storageArea: storage!,
},
}))
}
}
Expand All @@ -195,7 +210,7 @@ export function useStorage<T extends(string | number | boolean | object | null)>
}
}

function read(event?: StorageEvent) {
function read(event?: StorageEventLike) {
const rawValue = event
? event.newValue
: storage!.getItem(key)
Expand All @@ -221,7 +236,11 @@ export function useStorage<T extends(string | number | boolean | object | null)>
}
}

function update(event?: StorageEvent) {
function updateFromCustomEvent(event: CustomEvent<StorageEventLike>) {
update(event.detail)
}

function update(event?: StorageEventLike) {
if (event && event.storageArea !== storage)
return

Expand Down

0 comments on commit c6185bf

Please sign in to comment.