store 内容的持久化

对 store 内容的持久化一般是将其保存到 localStorage 里,这就要求所要保存的内容是可以被 JSON.stringify 序列化的。符合这个条件的话,就可以使用以下形式来定义一个可以自动将状态保存到 localStorage 的 store,并且支持状态的实时更新。

const state = proxy({
  JSON.parse(localStorage.getItem('state')) || {
    count: 0
  },
});

subscribe(state, () => {
  localStorage.setItem('state', JSON.stringify(state));
});

使用 valtio-persist 简化操作

为了简化持久化的操作,可以使用 valtio-persist 库来简化 store 的定义。在安装 valtio-persist 库之后,上面的示例可以简化为以下形式。

import { persist } from "valtio-persist";

interface State {
  count: number;
}

const { store } = await persist<State>(
  {
    count: 0,
  },
  "state"
);

persist 函数所接受的第一个参数为这个 store 的初始状态,第二个参数为这个 store 保存到持久化存储的键名。在使用 persist 函数完成 store 的定义以后,这个 store 就可以像普通的 store 一样使用了。

如果需要将 store 的内容持久化到 localStorage 以外的地方,可以向 persist 函数提供第三个参数。这个参数接受一个对象,可以在其中使用 storageStrategy 来定义所要持久化的位置,例如 { storageStrategy: IndexedDbStrategy },就可以将 store 的内容持久化到 IndexedDB 中。在默认情况下,valtio-persist 会使用 localStorage 作为持久化存储的位置。

valtio-persist 中可以使用的持久化存储位置可以有以下选择,注意其中部分策略可能需要额外的依赖。

存储位置策略名称依赖
localStorageLocalStorageStrategyvaltio-persist
sessionStorageSessionStorageStrategyvaltio-persist
IndexedDBIndexedDbStrategyvaltio-persist/indexed-db
MemoryMemoryStorageStrategyvaltio-persist

除了可以配置存储位置以外,valtio-persist 还提供了 store 内容合并方法、条件持久化以及手动控制等功能。

在默认情况下,valtio-persist 采用浅比较的方式进行 store 内容的合并,这会跳过一些不能够序列化内容的检查,如果需要执行深比较合并,可以在 persist 的第三个参数中配置 { mergeStrategy: DeepMergeStrategy } 来完成切换。

在满足一定条件的情况下执行持久化的配置,是需要定义一个函数来进行判断的,这个函数可以通过第三个参数中的 shouldPersist 来传递给 persist

在 store 内容频繁更改的时候,可能需要减缓对持久化存储位置的操作 IO 压力,那么就可以使用 valtio-persist 提供的防抖功能来实现,这项功能可以在第三个参数中通过提供 debounceTime 的值来设定 valtio-persist 的防抖等待时间。

persist 函数返回的内容是一个对象,在之前的示例中只使用了其中的 store 属性,除了 store 属性以外,这个返回的对象里还有 persistrestoreclear 三个方法。其中 persist 用于立刻将当前的状态持久化到指定的存储位置,restore 用于从指定的存储位置恢复状态,clear 用于清除指定的存储位置中的状态。这三个方法都是异步函数,在使用的时候注意要使用 await 关键字。