Skip to content

Commit a9b49f5

Browse files
authored
fix(useStorage): sync within the same document (#4152)
1 parent 42a4501 commit a9b49f5

File tree

2 files changed

+46
-13
lines changed

2 files changed

+46
-13
lines changed

packages/core/useStorage/index.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,4 +527,27 @@ describe('useStorage', () => {
527527
const objectRef = useStorage(KEY, value, storage)
528528
expect(objectRef.value).toEqual(value)
529529
})
530+
531+
it('syncs properly within the same document', async () => {
532+
const state1 = useStorage(KEY, 0, storage)
533+
const state2 = useStorage(KEY, 0, storage)
534+
535+
state1.value = 1
536+
await nextTick()
537+
expect(state2.value).toBe(1)
538+
})
539+
540+
it('syncs properly within the same document (custom storages)', async () => {
541+
const customStorage = {
542+
getItem: storage.getItem,
543+
setItem: storage.setItem,
544+
removeItem: storage.removeItem,
545+
}
546+
const state1 = useStorage(KEY, 0, customStorage)
547+
const state2 = useStorage(KEY, 0, customStorage)
548+
549+
state1.value = 1
550+
await nextTick()
551+
expect(state2.value).toBe(1)
552+
})
530553
})

packages/core/useStorage/index.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export function useStorage<T = unknown>(key: string, defaults: MaybeRefOrGetter<
132132
*
133133
* @see https://vueuse.org/useStorage
134134
*/
135-
export function useStorage<T extends(string | number | boolean | object | null)>(
135+
export function useStorage<T extends (string | number | boolean | object | null)>(
136136
key: string,
137137
defaults: MaybeRefOrGetter<T>,
138138
storage: StorageLike | undefined,
@@ -179,7 +179,14 @@ export function useStorage<T extends(string | number | boolean | object | null)>
179179

180180
if (window && listenToStorageChanges) {
181181
tryOnMounted(() => {
182-
// this should be fine since we are in a mounted hook
182+
/**
183+
* Attaching event listeners here should be fine since we are in a mounted hook
184+
*
185+
* The custom event is needed for same-document syncing when using custom
186+
* storage backends, but it doesn't work across different documents.
187+
*
188+
* TODO: Consider implementing a BroadcastChannel-based solution that fixes this.
189+
*/
183190
if (storage instanceof Storage)
184191
useEventListener(window, 'storage', update)
185192
else
@@ -196,17 +203,20 @@ export function useStorage<T extends(string | number | boolean | object | null)>
196203

197204
function dispatchWriteEvent(oldValue: string | null, newValue: string | null) {
198205
// send custom event to communicate within same page
199-
// importantly this should _not_ be a StorageEvent since those cannot
200-
// be constructed with a non-built-in storage area
201-
if (window && !(storage instanceof Storage)) {
202-
window.dispatchEvent(new CustomEvent<StorageEventLike>(customStorageEventName, {
203-
detail: {
204-
key,
205-
oldValue,
206-
newValue,
207-
storageArea: storage!,
208-
},
209-
}))
206+
if (window) {
207+
const payload = {
208+
key,
209+
oldValue,
210+
newValue,
211+
storageArea: storage as Storage,
212+
}
213+
// We also use a CustomEvent since StorageEvent cannot
214+
// be constructed with a non-built-in storage area
215+
window.dispatchEvent(storage instanceof Storage
216+
? new StorageEvent('storage', payload)
217+
: new CustomEvent<StorageEventLike>(customStorageEventName, {
218+
detail: payload,
219+
}))
210220
}
211221
}
212222

0 commit comments

Comments
 (0)