網址保留
「recoil-sync
」套件提供的其中一個內建外部儲存同步機制是網址保留。這讓使用者能夠輕易根據網址初始化原子、在原子變異時更新網址,以及訂閱網址變更(例如返回按鈕)。原子狀態變更可以設定為取代目前的網址,或推播一個新輸入到瀏覽器歷程紀錄堆疊中。
範例
以下是指定一個原子應與網址同步的簡單範例
const currentUserState = atom<number>({
key: 'CurrentUser',
default: 0,
effects: [syncEffect({ refine: number() })],
});
然後,在應用程式的根目錄中,只要包含 <RecoilURLSyncJSON>
,就可以讓所有那些標記的原子與網址同步
function MyApp() {
return (
<RecoilRoot>
<RecoilURLSyncJSON location={{part: 'queryParams'}}>
...
</RecoilURLSyncJSON>
</RecoilRoot>
)
}
https://test.com/myapp?CurrentUser=123
網址編碼
狀態序列化
有兩種內建機制可於網址中編碼狀態
- 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 中移除其他的查詢參數。
推播對比替換
預設情況下,任何原子變異都會將瀏覽器中的目前 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() })],
});