8000 feat(useStorage): make storage key reactive (#4464) · vueuse/vueuse@eb6797a · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Commit eb6797a

Browse files
EvgenyWasantfu
andauthored
feat(useStorage): make storage key reactive (#4464)
Co-authored-by: Anthony Fu <github@antfu.me>
1 parent dd316da commit eb6797a

File tree

5 files changed

+83
-27
lines changed

5 files changed

+83
-27
lines changed

packages/core/useLocalStorage/index.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import type { UseStorageOptions } from '../useStorage'
33
import { defaultWindow } from '../_configurable'
44
import { useStorage } from '../useStorage'
55

6-
export function useLocalStorage(key: string, initialValue: MaybeRefOrGetter<string>, options?: UseStorageOptions<string>): RemovableRef<string>
7-
export function useLocalStorage(key: string, initialValue: MaybeRefOrGetter<boolean>, options?: UseStorageOptions<boolean>): RemovableRef<boolean>
8-
export function useLocalStorage(key: string, initialValue: MaybeRefOrGetter<number>, options?: UseStorageOptions<number>): RemovableRef<number>
9-
export function useLocalStorage<T>(key: string, initialValue: MaybeRefOrGetter<T>, options?: UseStorageOptions<T>): RemovableRef<T>
10-
export function useLocalStorage<T = unknown>(key: string, initialValue: MaybeRefOrGetter<null>, options?: UseStorageOptions<T>): RemovableRef<T>
6+
export function useLocalStorage(key: MaybeRefOrGetter<string>, initialValue: MaybeRefOrGetter<string>, options?: UseStorageOptions<string>): RemovableRef<string>
7+
export function useLocalStorage(key: MaybeRefOrGetter<string>, initialValue: MaybeRefOrGetter<boolean>, options?: UseStorageOptions<boolean>): RemovableRef<boolean>
8+
export function useLocalStorage(key: MaybeRefOrGetter<string>, initialValue: MaybeRefOrGetter<number>, options?: UseStorageOptions<number>): RemovableRef<number>
9+
export function useLocalStorage<T>(key: MaybeRefOrGetter<string>, initialValue: MaybeRefOrGetter<T>, options?: UseStorageOptions<T>): RemovableRef<T>
10+
export function useLocalStorage<T = unknown>(key: MaybeRefOrGetter<string>, initialValue: MaybeRefOrGetter<null>, options?: UseStorageOptions<T>): RemovableRef<T>
1111

1212
/**
1313
* Reactive LocalStorage.
@@ -18,7 +18,7 @@ export function useLocalStorage<T = unknown>(key: string, initialValue: MaybeRef
1818
* @param options
1919
*/
2020
export function useLocalStorage<T extends(string | number | boolean | object | null)>(
21-
key: string,
21+
key: MaybeRefOrGetter<string>,
2222
initialValue: MaybeRefOrGetter<T>,
2323
options: UseStorageOptions<T> = {},
2424
): RemovableRef<any> {

packages/core/useSessionStorage/index.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import type { UseStorageOptions } from '../useStorage'
33
import { defaultWindow } from '../_configurable'
44
import { useStorage } from '../useStorage'
55

6-
export function useSessionStorage(key: string, initialValue: MaybeRefOrGetter<string>, options?: UseStorageOptions<string>): RemovableRef<string>
7-
export function useSessionStorage(key: string, initialValue: MaybeRefOrGetter<boolean>, options?: UseStorageOptions<boolean>): RemovableRef<boolean>
8-
export function useSessionStorage(key: string, initialValue: MaybeRefOrGetter<number>, options?: UseStorageOptions<number>): RemovableRef<number>
9-
export function useSessionStorage<T>(key: string, initialValue: MaybeRefOrGetter<T>, options?: UseStorageOptions<T>): RemovableRef<T>
10-
export function useSessionStorage<T = unknown>(key: string, initialValue: MaybeRefOrGetter<null>, options?: UseStorageOptions<T>): RemovableRef<T>
6+
export function useSessionStorage(key: MaybeRefOrGetter<string>, initialValue: MaybeRefOrGetter<string>, options?: UseStorageOptions<string>): RemovableRef<string>
7+
export function useSessionStorage(key: MaybeRefOrGetter<string>, initialValue: MaybeRefOrGetter<boolean>, options?: UseStorageOptions<boolean>): RemovableRef<boolean>
8+
export function useSessionStorage(key: MaybeRefOrGetter<string>, initialValue: MaybeRefOrGetter<number>, options?: UseStorageOptions<number>): RemovableRef<number>
9+
export function useSessionStorage<T>(key: MaybeRefOrGetter<string>, initialValue: MaybeRefOrGetter<T>, options?: UseStorageOptions<T>): RemovableRef<T>
10+
export function useSessionStorage<T = unknown>(key: MaybeRefOrGetter<string>, initialValue: MaybeRefOrGetter<null>, options?: UseStorageOptions<T>): RemovableRef<T>
1111

1212
/**
1313
* Reactive SessionStorage.
@@ -18,7 +18,7 @@ export function useSessionStorage<T = unknown>(key: string, initialValue: MaybeR
1818
* @param options
1919
*/
2020
export function useSessionStorage<T extends(string | number | boolean | object | null)>(
21-
key: string,
21+
key: MaybeRefOrGetter<string>,
2222
initialValue: MaybeRefOrGetter<T>,
2323
options: UseStorageOptions<T> = {},
2424
): RemovableRef<any> {

packages/core/useStorage/index.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ const count = useStorage('my-count', 0) // returns Ref<number>
2929

3030
// bind string with SessionStorage
3131
const id = useStorage('my-id', 'some-string-id', sessionStorage) // returns Ref<string>
32-
3332
// delete data from storage
3433
state.value = null
3534
```

packages/core/useStorage/index.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { customStorageEventName, StorageSerializers, useStorage } from '.'
55
import { mount, nextTwoTick, useSetup } from '../../.test'
66

77
const KEY = 'custom-key'
8+
const ANOTHER_KEY = 'another-key'
89

910
vi.mock('../ssr-handlers', () => ({
1011
getSSRHandler: vi.fn().mockImplementationOnce((_, cb) => () => cb()).mockImplementationOnce(() => () => {
@@ -547,4 +548,57 @@ describe('useStorage', () => {
547548
await nextTick()
548549
expect(state2.value).toBe(1)
549550
})
551+
552+
it('updates on key change when thew new storage value is presented', async () => {
553+
storage.setItem(ANOTHER_KEY, '1')
554+
const key = ref(KEY)
555+
const data = useStorage(key, 0, storage)
556+
557+
data.value = 2
558+
await nextTick()
559+
key.value = ANOTHER_KEY
560+
await nextTick()
561+
expect(data.value).toBe(1)
562+
expect(storage.getItem(KEY)).toBe('2')
563+
expect(storage.getItem(ANOTHER_KEY)).toBe('1')
564+
565+
key.value = KEY
566+
data.value = 3
567+
await nextTick()
568+
expect(storage.getItem(KEY)).toBe('2')
569+
expect(storage.getItem(ANOTHER_KEY)).toBe('1')
570+
})
571+
572+
it('changes to defaults on key change when the new storage value is undefined', async () => {
573+
const key = ref(KEY)
574+
const data = useStorage(key, 0, storage)
575+
576+
data.value = 1
577+
key.value = ANOTHER_KEY
578+
await nextTick()
579+
expect(data.value).toBe(1)
580+
expect(storage.getItem(KEY)).toBe('0')
581+
expect(storage.getItem(ANOTHER_KEY)).toBe('1')
582+
583+
data.value = 2
584+
await nextTick()
585+
key.value = KEY
586+
await nextTick()
587+
expect(data.value).toBe(0)
588+
expect(storage.getItem(KEY)).toBe('0')
589+
expect(storage.getItem(ANOTHER_KEY)).toBe('2')
590+
})
591+
592+
it('listens to new storage value changes after key change', async () => {
593+
const key = ref(KEY)
594+
const data = useStorage(key, 0, localStorage)
595+
596+
key.value = ANOTHER_KEY
597+
await nextTick()
598+
expect(data.value).toBe(0)
599+
600+
window.dispatchEvent(new StorageEvent('storage', { storageArea: localStorage, key: ANOTHER_KEY, newValue: '1' }))
601+
window.dispatchEvent(new StorageEvent('storage', { storageArea: localStorage, key: KEY, newValue: '2' }))
602+
expect(data.value).toBe(1)
603+
})
550604
})

packages/core/useStorage/index.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Awaitable, ConfigurableEventFilter, ConfigurableFlush, MaybeRefOrG
22
import type { ConfigurableWindow } from '../_configurable'
33
import type { StorageLike } from '../ssr-handlers'
44
import { pausableWatch, tryOnMounted } from '@vueuse/shared'
5-
import { nextTick, ref, shallowRef, toValue } from 'vue'
5+
import { computed, nextTick, ref, shallowRef, toValue, watch } from 'vue'
66
import { defaultWindow } from '../_configurable'
77
import { getSSRHandler } from '../ssr-handlers'
88
import { useEventListener } from '../useEventListener'
@@ -121,19 +121,19 @@ export interface UseStorageOptions<T> extends ConfigurableEventFilter, Configura
121121
initOnMounted?: boolean
122122
}
123123

124-
export function useStorage(key: string, defaults: MaybeRefOrGetter<string>, storage?: StorageLike, options?: UseStorageOptions<string>): RemovableRef<string>
125-
export function useStorage(key: string, defaults: MaybeRefOrGetter<boolean>, storage?: StorageLike, options?: UseStorageOptions<boolean>): RemovableRef<boolean>
126-
export function useStorage(key: string, defaults: MaybeRefOrGetter<number>, storage?: StorageLike, options?: UseStorageOptions<number>): RemovableRef<number>
127-
export function useStorage<T>(key: string, defaults: MaybeRefOrGetter<T>, storage?: StorageLike, options?: UseStorageOptions<T>): RemovableRef<T>
128-
export function useStorage<T = unknown>(key: string, defaults: MaybeRefOrGetter<null>, storage?: StorageLike, options?: UseStorageOptions<T>): RemovableRef<T>
124+
export function useStorage(key: MaybeRefOrGetter<string>, defaults: MaybeRefOrGetter<string>, storage?: StorageLike, options?: UseStorageOptions<string>): RemovableRef<string>
125+
export function useStorage(key: MaybeRefOrGetter<string>, defaults: MaybeRefOrGetter<boolean>, storage?: StorageLike, options?: UseStorageOptions<boolean>): RemovableRef<boolean>
126+
export function useStorage(key: MaybeRefOrGetter<string>, defaults: MaybeRefOrGetter<number>, storage?: StorageLike, options?: UseStorageOptions<number>): RemovableRef<number>
127+
export function useStorage<T>(key: MaybeRefOrGetter<string>, defaults: MaybeRefOrGetter<T>, storage?: StorageLike, options?: UseStorageOptions<T>): RemovableRef<T>
128+
export function useStorage<T = unknown>(key: MaybeRefOrGetter<string>, defaults: MaybeRefOrGetter<null>, storage?: StorageLike, options?: UseStorageOptions<T>): RemovableRef<T>
129129

130130
/**
131131
* Reactive LocalStorage/SessionStorage.
132132
*
133133
* @see https://vueuse.org/useStorage
134134
*/
135135
export function useStorage<T extends (string | number | boolean | object | null)>(
136-
key: string,
136+
key: MaybeRefOrGetter<string>,
137137
defaults: MaybeRefOrGetter<T>,
138138
storage: StorageLike | undefined,
139139
options: UseStorageOptions<T> = {},
@@ -154,6 +154,7 @@ export function useStorage<T extends (string | number | boolean | object | null)
154154
} = options
155155

156156
const data = (shallow ? shallowRef : ref)(typeof defaults === 'function' ? defaults() : defaults) as RemovableRef<T>
157+
const keyComputed = computed<string>(() => toValue(key))
157158

158159
if (!storage) {
159160
try {
@@ -177,6 +178,8 @@ export function useStorage<T extends (string | number | boolean | object | null)
177178
{ flush, deep, eventFilter },
178179
)
179180

181+
watch(keyComputed, () => update(), { flush })
182+
180183
if (window && listenToStorageChanges) {
181184
tryOnMounted(() => {
182185
/**
@@ -205,7 +208,7 @@ export function useStorage<T extends (string | number | boolean | object | null)
205208
// send custom event to communicate within same page
206209
if (window) {
207210
const payload = {
208-
key,
211+
key: keyComputed.value,
209212
oldValue,
210213
newValue,
211214
storageArea: storage as Storage,
@@ -222,16 +225,16 @@ export function useStorage<T extends (string | number | boolean | object | null)
222225

223226
function write(v: unknown) {
224227
try {
225-
const oldValue = storage!.getItem(key)
228+
const oldValue = storage!.getItem(keyComputed.value)
226229

227230
if (v == null) {
228231
dispatchWriteEvent(oldValue, null)
229-
storage!.removeItem(key)
232+
storage!.removeItem(keyComputed.value)
230233
}
231234
else {
232235
const serialized = serializer.write(v as any)
233236
if (oldValue !== serialized) {
234-
storage!.setItem(key, serialized)
237+
storage!.setItem(keyComputed.value, serialized)
235238
dispatchWriteEvent(oldValue, serialized)
236239
}
237240
}
@@ -244,11 +247,11 @@ export function useStorage<T extends (string | number | boolean | object | null)
244247
function read(event?: StorageEventLike) {
245248
const rawValue = event
246249
? event.newValue
247-
: storage!.getItem(key)
250+
: storage!.getItem(keyComputed.value)
248251

249252
if (rawValue == null) {
250253
if (writeDefaults && rawInit != null)
251-
storage!.setItem(key, serializer.write(rawInit))
254+
storage!.setItem(keyComputed.value, serializer.write(rawInit))
252255
return rawInit
253256
}
254257
else if (!event && mergeDefaults) {
@@ -276,7 +279,7 @@ export function useStorage<T extends (string | number | boolean | object | null)
276279
return
277280
}
278281

279-
if (event && event.key !== key)
282+
if (event && event.key !== keyComputed.value)
280283
return
281284

282285
pauseWatch()

0 commit comments

Comments
 (0)
0