跳至主要内容

URL 持久化

recoil-sync 包提供了几种内置的外部存储同步机制,其中之一就是 URL 持久化。这使得用户可以轻松地根据 URL 初始化原子,在原子发生变化时更新 URL,以及订阅 URL 变化(例如后退按钮)。可以配置原子状态变化以替换当前 URL 或将新条目推送到浏览器历史记录堆栈中。

示例

以下是一个指定原子应与 URL 同步的简单示例

const currentUserState = atom<number>({
key: 'CurrentUser',
default: 0,
effects: [syncEffect({ refine: number() })],
});

然后,在应用程序的根目录中,只需包含 <RecoilURLSyncJSON> 即可将所有这些带标签的原子与 URL 同步。

function MyApp() {
return (
<RecoilRoot>
<RecoilURLSyncJSON location={{part: 'queryParams'}}>
...
</RecoilURLSyncJSON>
</RecoilRoot>
)
}
https://test.com/myapp?CurrentUser=123

URL 编码

状态序列化

有两种内置机制可用于在 URL 中对状态进行编码

  • JSON - 使用 <RecoilURLSyncJSON>JSON 编码 简单易读。但是它不支持自定义用户类或容器,例如 Map()Set()。如果您使用 Refine 中的 jsonDate() 检查器,它将与 Date 对象一起使用。
  • Transit - 使用 <RecoilURLSyncTransit>Transit 编码 稍微冗长一些,但它支持 Map()Set() 容器,并且可以通过提供自定义处理程序来扩展以编码您自己的类。

您也可以使用基本 <RecoilURLSync> 实现并提供您自己的 serialize()deserialize() 实现。

URL 的一部分

可以配置状态将与 URL 的哪一部分同步。 location 属性可以指定这一点,例如 {part: 'hash'} 在锚标记中存储,{part: 'queryParams'} 作为单独的查询参数存储,或者 {part: 'queryParams', param: 'myParam'} 在单个查询参数中进行编码。该库将尝试共存,并且不会从 URL 中删除其他查询参数。

推 vs 替换

默认情况下,任何原子变异都会用更新后的状态替换浏览器中的当前 URL。您也可以使用 urlSyncEffect() 效果而不是 syncEffect() 来指定其他选项,例如此状态的变化是否应该导致新的 URL 被推送到浏览器历史记录堆栈中。这允许使用浏览器的后退按钮来撤消这些状态更改。

const currentViewState = atom<string>({
key: 'CurrentView',
default: 'index',
effects: [urlSyncEffect({ refine: number(), history: 'push' })],
});

多种编码

请记住,您可以将不同的原子与不同的存储混合搭配使用。因此,您可以将某些原子编码为它们自己的查询参数,以便于阅读和解析,而将其余状态放置在一个使用 Transit 编码用户类的单个查询参数中。

class ViewState {
active: boolean;
pos: [number, number];
constructor(active, pos) {
this.active = active;
this.pos = pos;
}
...
};
const viewStateChecker = custom(x => x instanceof ViewState ? x : null);

function MyApp() {
return (
<RecoilRoot>
<RecoilURLSyncJSON storeKey="json-url" location={{part: 'queryParams'}}>
<RecoilURLSyncTransit
storeKey="transit-url"
location={{part: 'queryParam', param: 'state'}}
handlers={[
{
tag: 'VS',
class: ViewState,
write: x => [x.active, x.pos],
read: ([active, pos]) => new ViewState(active, pos),
},
]}
/>
...
</RecoilURLSyncTransit>
</RecoilURLSyncJSON>
</RecoilRoot>
)
}

const currentUserState = atom<number>({
key: 'CurrentUser',
default: 0,
effects: [syncEffect({ storeKey: 'json-url', refine: number() })],
});

const ViewState = atom<ViewState>({
key: 'ViewState',
default: new ViewState(),
effects: [syncEffect({ storeKey: 'transit-url', refine: viewStateChecker() })],
});