我这段时间在做 Tauri 本地应用,目前数据通过状态管理库(zustand) + tauri-plugin-store 持久化到本地文件中,后来我为了安全,做了一个数据导入、导出的功能,但完成后我就觉得不太对劲,好像整个流程上存在问题,我不知道最佳实践是什么样的。
或者可以这样说吧,我现在的数据是持久化到文件的,我想要把他保存在云端(等其他地方),并且支持从这些数据源恢复数据,同时也有数据迁移。
先说一下状态管理库持久化的情况:
{
name: 'name',
// 持久化的一些方法
storage: createJSONStorage(() => appStorage),
// 最新的版本号
version: VERSION,
// 需要持久化的字段
partialize: (state) => ({ scripts: state.scripts }),
// 数据迁移函数
migrate: (persistedState: any, version) => {
// 持久化数据的版本号,会重复执行这个 migrate 函数直到两个版本号一致
if (version === 0) {
// 数据迁移
return persistedState
}
return persistedState
}
}
// appStore 的实现,用于适配多种数据库
(store) => ({
getItem: async (name: string): Promise<string | null> => {},
setItem: async (name: string, value: string): Promise<void> => {},
removeItem: async (name: string): Promise<void> => {},
})
我的数据不需要维护版本号之类的信息,这些都是 zustand 帮我维护的,所以最终保存到本地的数据大概是这样的:
{
version: number,
state: {
// zustand 实际存的数据
scripts: []
}
}
如果要上传,那么肯定是上传 scripts
列表,也就是数据本体,这样拉回数据的时候,可以直接写入 zustand store,但这样做的话,version
就没了,那就分不清楚这个数据是什么版本下上传的了。
如果我带上 version
一起上传,这样数据恢复时,似乎需要我手动去调用 migrate
函数进行迁移。。。
写完找到灵感了,就带上 version
保存,把 migrate
函数提取出去复用,恢复数据的时候通过 restore
函数调用 migrate
进行迁移:
function restore(state, ver) {
// 确保初始版本号小于或等于目标版本号,避免逻辑错误
if (ver > VERSION) {
console.error("云端数据版本号大于最新版");
return;
}
let currentState = state;
for (let currentVer = ver; currentVer < VERSION; currentVer++) {
currentState = migrate(currentState, currentVer);
console.log(`成功迁移到版本 ${currentVer + 1}`);
}
// 确保最终版本与预期相符
if (currentState.version !== VERSION) {
console.warn("迁移函数不完整");
} else {
console.log("数据迁移完成");
}
return currentState;
}