Skip to content

useStorage

Category
Export Size
1.78 kB
Last Changed
last month
Related

创建一个响应式的 ref,用于访问和修改 LocalStorageSessionStorage

默认使用 localStorage,可以通过第三个参数指定其他存储源。

Demo

name: Banana
color: Yellow
size: Medium
count: 0

用法

TIP

当与 Nuxt 3 一起使用时,此函数将不会自动导入,以支持 Nitro 内置的 useStorage()。如果你想使用 VueUse 中的函数,请显式导入。

js
import { useStorage } from '@vueuse/core'

// 绑定对象
const state = useStorage('my-store', { hello: 'hi', greeting: 'Hello' })

// 绑定布尔值
const flag = useStorage('my-flag', true) // 返回 Ref<boolean>

// 绑定数字
const count = useStorage('my-count', 0) // 返回 Ref<number>

// 使用 SessionStorage 绑定字符串
const id = useStorage('my-id', 'some-string-id', sessionStorage) // 返回 Ref<string>
// 从存储中删除数据
state.value = null

合并默认值

默认情况下,useStorage 会使用存储中的值(如果存在)并忽略默认值。请注意,当你向默认值添加更多属性时,如果客户端的存储中没有该键,则该键可能为 undefined

ts
localStorage.setItem('my-store', '{"hello": "hello"}')

const state = useStorage('my-store', { hello: 'hi', greeting: 'hello' }, localStorage)

console.log(state.value.greeting) // undefined,因为存储中没有这个值

要解决这个问题,你可以启用 mergeDefaults 选项。

ts
localStorage.setItem('my-store', '{"hello": "nihao"}')

const state = useStorage(
  'my-store',
  { hello: 'hi', greeting: 'hello' },
  localStorage,
  { mergeDefaults: true } // <--
)

console.log(state.value.hello) // 'nihao',来自存储
console.log(state.value.greeting) // 'hello',来自合并的默认值
js
localStorage.setItem('my-store', '{"hello": "nihao"}')
const state = useStorage(
  'my-store',
  { hello: 'hi', greeting: 'hello' },
  localStorage,
  { mergeDefaults: true },
)
console.log(state.value.hello) // 'nihao',来自存储
console.log(state.value.greeting) // 'hello',来自合并的默认值

当设置为 true 时,将对对象执行浅合并。你可以传递一个函数来执行自定义合并(例如深度合并),例如:

ts
const state = useStorage(
  'my-store',
  { hello: 'hi', greeting: 'hello' },
  localStorage,
  { mergeDefaults: (storageValue, defaults) => deepMerge(defaults, storageValue) } // <--
)
js
const state = useStorage(
  'my-store',
  { hello: 'hi', greeting: 'hello' },
  localStorage,
  {
    mergeDefaults: (storageValue, defaults) =>
      deepMerge(defaults, storageValue),
  },
)

自定义序列化

默认情况下,useStorage 会根据提供的默认值的数据类型智能地使用相应的序列化器。例如,对于对象使用 JSON.stringify / JSON.parse,对于数字使用 Number.toString / parseFloat 等。

你也可以为 useStorage 提供自己的序列化函数:

ts
import { useStorage } from '@vueuse/core'

useStorage(
  'key',
  {},
  undefined,
  {
    serializer: {
      read: (v: any) => v ? JSON.parse(v) : null,
      write: (v: any) => JSON.stringify(v),
    },
  },
)
js
import { useStorage } from '@vueuse/core'
useStorage('key', {}, undefined, {
  serializer: {
    read: (v) => (v ? JSON.parse(v) : null),
    write: (v) => JSON.stringify(v),
  },
})

请注意,当你提供 null 作为默认值时,useStorage 无法从中推断数据类型。在这种情况下,你可以提供自定义序列化器或显式重用内置的序列化器。

ts
import { StorageSerializers, useStorage } from '@vueuse/core'

const objectLike = useStorage('key', null, undefined, { serializer: StorageSerializers.object })
objectLike.value = { foo: 'bar' }

Type Declarations

Show Type Declarations
typescript
export interface Serializer<T> {
  read: (raw: string) => T
  write: (value: T) => string
}
export interface SerializerAsync<T> {
  read: (raw: string) => Awaitable<T>
  write: (value: T) => Awaitable<string>
}
export declare const StorageSerializers: Record<
  "boolean" | "object" | "number" | "any" | "string" | "map" | "set" | "date",
  Serializer<any>
>
export declare 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
   *
   * @default true
   */
  deep?: boolean
  /**
   * Listen to storage changes, useful for multiple tabs application
   *
   * @default true
   */
  listenToStorageChanges?: boolean
  /**
   * Write the default value to the storage when it does not exist
   *
   * @default true
   */
  writeDefaults?: boolean
  /**
   * Merge the default value with the value read from the storage.
   *
   * When setting it to true, it will perform a **shallow merge** for objects.
   * You can pass a function to perform custom merge (e.g. deep merge), for example:
   *
   * @default false
   */
  mergeDefaults?: boolean | ((storageValue: T, defaults: T) => T)
  /**
   * Custom data serialization
   */
  serializer?: Serializer<T>
  /**
   * On error callback
   *
   * Default log error to `console.error`
   */
  onError?: (error: unknown) => void
  /**
   * Use shallow ref as reference
   *
   * @default false
   */
  shallow?: boolean
  /**
   * Wait for the component to be mounted before reading the storage.
   *
   * @default false
   */
  initOnMounted?: boolean
}
export declare function useStorage(
  key: MaybeRefOrGetter<string>,
  defaults: MaybeRefOrGetter<string>,
  storage?: StorageLike,
  options?: UseStorageOptions<string>,
): RemovableRef<string>
export declare function useStorage(
  key: MaybeRefOrGetter<string>,
  defaults: MaybeRefOrGetter<boolean>,
  storage?: StorageLike,
  options?: UseStorageOptions<boolean>,
): RemovableRef<boolean>
export declare function useStorage(
  key: MaybeRefOrGetter<string>,
  defaults: MaybeRefOrGetter<number>,
  storage?: StorageLike,
  options?: UseStorageOptions<number>,
): RemovableRef<number>
export declare function useStorage<T>(
  key: MaybeRefOrGetter<string>,
  defaults: MaybeRefOrGetter<T>,
  storage?: StorageLike,
  options?: UseStorageOptions<T>,
): RemovableRef<T>
export declare function useStorage<T = unknown>(
  key: MaybeRefOrGetter<string>,
  defaults: MaybeRefOrGetter<null>,
  storage?: StorageLike,
  options?: UseStorageOptions<T>,
): RemovableRef<T>

Source

SourceDemoDocs

Contributors

Anthony Fu
Fernando Fernández
丶远方
Anthony Fu
IlyaL
sun0day
Jelf
Jeffrey Li
Robin
Yauheni Vasiukevich
OrbisK
Callum Macrae
Isaac Qadri
Matt Sanders
Doctorwu
Eduardo San Martin Morote
Daniel Maixner
chenglu
David Ma
Daniel Mittereder
Clément Ollivier
James Garbutt
Yury Rudey
Puru Vijay
webfansplz
spking11
Maurici Abad Gutierrez
Guillaume Chau
Denis Blazhkun
Andreas Weber
Le Minh Tri
Jamie Warburton
Shinigami
Sasan Farrokh
Pig Fang
wheat
Alex Kozack
Nurettin Kaya
Pine
Antério Vieira
Ivan Demchuk

Changelog

7432f - feat(types): deprecate MaybeRef and MaybeRefOrGetter in favor of Vue's native (#4636)
eb679 - feat: make storage key reactive (#4464)
dd316 - feat: use passive event handlers everywhere is possible (#4477)
59f75 - feat(toValue): deprecate toValue from @vueuse/shared in favor of Vue's native
0a9ed - feat!: drop Vue 2 support, optimize bundles and clean up (#4349)
a9b49 - fix: sync within the same document (#4152)
5a302 - feat: conditionally use event based on the used storage backend (#3822)
f7ea1 - fix: ensure setting value to null syncs to other instances (#3737)
a086e - fix: stricter types
04220 - fix: fix undefined defaults (#3597)
dc6f2 - feat: add waitOnMounted option for SSR (#3504)
b6d2b - fix: fix defaults not unwrapped (#3534)
6fabe - fix: read object only when it's serialized differently (#2782) (#3091)
cb644 - refactor!: remove isFunction and isString utils
4d757 - feat(types)!: rename MaybeComputedRef to MaybeRefOrGetter
0a72b - feat(toValue): rename resolveUnref to toValue

Released under the MIT License.