mobx进行持久化封装
使用场景
我在使用react+mobx进行状态管理的代码编写的时候,我发现有些数据数据需要web端持久化维护
1.不需要每次都向服务端获取的数据,例如Token,用户历史聊天记录等。
2.一些用户设置,例如,声音大小、UI主题选择、用户调整侧边栏的宽度等
如果需要对这些数据进行状态管理需要添加两部操作
1、在mobx的状态进行变化时,调用localStorage.setItem持久化存储。
2、在mobx的状态初始化时,调用localStorage.getItem获取存储值
简单封装
import { debounce } from '@/utils/common'
import { action, makeObservable, observable } from 'mobx'
const key = 'configInfoState'
/**
* 默认值
*/
const defaultValue = {
chatInputBoxHeight: 150,
leftTwoBarWidth: 300,
}
/**
* 获取本地存储的状态
* @returns
*/
const getLocal = (): ConfigInfoStateData => {
let data: ConfigInfoStateData
try {
data = JSON.parse(localStorage.getItem(key) || '')
if (!data.chatInputBoxHeight) {
throw new Error('parse Error')
}
} catch (e) {
data = defaultValue
}
return data
}
/**
* 使用防抖函数防止频繁写入本地存储
*/
const saveLocal = debounce((data: ConfigInfoStateData) => {
localStorage.setItem(key, JSON.stringify(data))
}, 1000)
type ConfigInfoStateData = typeof defaultValue
class ConfigInfoState {
value: ConfigInfoStateData = getLocal()
setValue<T extends keyof ConfigInfoStateData>(
key: T,
value: ConfigInfoStateData[T]
) {
this.value[key] = value
saveLocal(this.value)
}
constructor() {
makeObservable(this, {
value: observable,
setValue: action,
})
}
}
export const configInfoState = new ConfigInfoState()
这种简单封装可以让我们调用时无需再对持续化的工作进行考虑,但是每次使用创建一个状态都需要写一遍上面的代码,上面代码其实还可以优化,
封装优化
创建一个文件storageState.ts
import { debounce } from '@/utils/common'
import { action, makeObservable, observable } from 'mobx'
/**
* 获取缓存值
* @param defaultValue 获取失败的返回默认值
* @param key 密钥
* @returns
*/
const getLocal = <T>(defaultValue: T, key: string): T => {
let data: T
try {
const str = localStorage.getItem(key)
if (!str) {
return defaultValue
}
data = JSON.parse(str)
if (data == null) {
return defaultValue
}
} catch (e) {
data = defaultValue
}
return data
}
class StorageState<T extends object> {
value: T
private key: string
private defaultValue: T
private saveLocal: (data: T) => void
setValue<K extends keyof T>(key: K, value: T[K]) {
this.value[key] = value
this.saveLocal(this.value)
}
clear() {
this.value = this.defaultValue
this.saveLocal(this.value)
}
/**
*
* @param key 缓存密钥
* @param defaultValue 默认值
* @param persistenceDelay 持久化延迟
*/
constructor(key: string, defaultValue: T, persistenceDelay: number = 1000) {
if (defaultValue === null) {
throw new Error('new StorageState param defaultValue cannot be null')
}
this.key = '_storage_state_' + key
if (key.length < 5) {
console.log('key too short, please use a longer key')
}
this.value = getLocal<T>(defaultValue, this.key)
this.defaultValue = defaultValue
if (persistenceDelay <= 0) {
this.saveLocal = <T>(data: T) =>
localStorage.setItem(this.key, JSON.stringify(data))
} else {
this.saveLocal = debounce(
<T>(data: T) => localStorage.setItem(this.key, JSON.stringify(data)),
persistenceDelay
)
}
makeObservable(this, {
value: observable,
setValue: action,
})
}
}
export default StorageState
修改原来的configInfoState
import StorageState from '@/utils/StorageState'
const key = 'configInfoState'
const defaultValue = {
chatInputBoxHeight: 150,
leftTwoBarWidth: 300,
}
export const configInfoState = new StorageState(key, defaultValue)
这时候每次创建一个状态时,只需要初始化默认值和key的命名就可以了