你是否阅读过《你可能不需要 Vuex》或是《你可能不需要 Pinia》?使用 reactive 创建一个全局变量代替 Vuex 或 Pinia,作为全局状态。个人非常喜欢这么做,但没有与之配套的持久化数据方案,于是就产生了 Prorage。
Prorage 简介
项目地址:aweikalee/prorage
Prorage = Proxy + Storage。
让 localStorage 使用起来像对象一样自然。
基于 @vue/reactivity 实现的持久化数据管理,与 reactive 有着几乎相同的使用方式。与 @vue/reactivity 一样可以脱离 Vue 单独使用。
提供了插件系统,可以实现大部分定制化的需求。内置了有效期、数据转换的插件。
快速上手
Playground
安装
npm install @vue/reactivity
npm install prorage
如果你已经安装了 Vue,则不需要再安装 @vue/reactivity。
使用
import { createStorage, expiresPlugin } from 'prorage'
const storage = createStorage()
storage.foo = 'foo'
delete foo
storage.bar = []
storage.bar.push('hello')
特性
更丰富的数据类型支持
localStorage 只支持字符串,通常会使用 JSON.stringify/JSON.parse 对数据处理。
Prorage 在 JSON.stringify/JSON.parse 基础上,以插件(translatePlugin)的形式提供了更多的类型支持。
基础类型支持情况对比:
| 数据类型 | localStorage | JSON.stringify | Prorage with translatePlugin |
|---|---|---|---|
| undefined | ✔️ | ✔️ | ✔️ |
| null | ✔️ | ✔️ | ✔️ |
| String | ❌ | ✔️ | ✔️ |
| Boolean | ❌ | ✔️ | ✔️ |
| Number | ❌ | ✔️,但不支持 NaN/Infinity/-Infinity | ✔️ |
| BigInt | ❌ | ❌ | ✔️ |
| Symbol | ❌ | ❌ | 可以支持 Symbol.for (需用户配置) |
此外还增加了 Date, RegExp 的支持。如果还不满足,则可以通过 translatePlugin 设置更多的类型支持。
Set/Map实现成本与收益不匹配,并未支持。而WeakSet/WeakMap则因实现没有意义,也未支持。
有效期
localStorage 不支持设置数据有效期。
Prorage 的 expiresPlugin 插件则提供了设置有效期的支持。
import { createStorage, expiresPlugin, useExpires, getExtra } from 'prorage'
const storage = createStorage({
plugins: [expiresPlugin()]
})
storage.foo = useExpires('bar', { days: 7 })
console.log(storage.foo) // 'bar'
// 7天后
console.log(storage.foo) // undefined
和通常的有效期方案不同的是,Prorage 中存在两种有效期检查,一是在数据被读取时检查,二是设置了定时器定期检查,过期的数据将会被拦截/删除。这使得 Prorage 能更好得配合前端框架,及时更新视图。
定制化
Prorage 提供了较大的定制空间。
const storage = createStorage({
storage: localStorage,
stringify: JSON.stringify,
parse: JSON.parse,
prefix: 'prefix#',
plugins: [expiresPlugin()]
})
| 参数 | 说明 |
|---|---|
| storage | 储存对象 可替换为 sessionStorage 或是其他 StorageLike |
| stringify | 转换为 JSON 字符串的方法 |
| parse | 解析 JSON 字符串的方法 |
| prefix | 储存键名前缀 |
| plugins | 插件 |
Plugin 插件
插件可声明一系列 Hook,在特定时机被调用。通过插件,可以实现大部分定制化的需求。
插件的详细说明请看文档。
循环引用
可以借助 flatted 之类的 JSON 库来解决循环引用的问题.
import { stringify, parse, } from 'flatted'
import { createStorage } from 'prorage'
const storage = createStorage({
stringify,
parse,
})
storage.test = {}
storage.test.circular = storage.test
与 Vue 一起使用
Prorage 完全可以当做 reactive 对象使用。
import { watch, computed } from 'vue'
import { createStorage } from 'prorage'
const storage = createStorage()
const foo = computed(() => storage.foo)
watch(() => storage.bar, (value) => {
console.log(`[bar changed]: ${value}`)
})
与 React 一起使用
就和 @vue/reactivity 在 React 中使用一样,以下是一种简单的使用示例:Prorage With React - StackBlitz。
写在后面
如果你也不爱使用 Vuex/Pinia,不妨试试使用 Prorage 管理持久化数据。
当然如果你的项目使用了 Vuex/Pinia,那还是更建议使用配套的持久化数据插件。
你有什么想法或建议,欢迎交流。