我們很榮幸地宣布推出 Recoil 0.4,其中包含可設置選擇器快取、改進用於多個原子進行交易的 API,以及其他最佳化和修正。
可設定的選擇器快取
新增至 選擇器 及 選擇器元組 的 cachePolicy_UNSTABLE
屬性,讓你能夠設定選擇器內部快取的快取行為。此屬性可以用於降低有大量選擇器或選擇器有很多變更相依項之應用程式的記憶體用量。
下方示範這個新屬性如何使用
const clockState = selector({
key: 'clockState',
get: ({get}) => {
const hour = get(hourState);
const minute = get(minuteState);
const second = get(secondState); // will re-run every second
return `${hour}:${minute}:${second}`;
},
cachePolicy_UNSTABLE: {
// Only store the most recent set of dependencies and their values
eviction: 'most-recent',
},
});
在上例中,clockState
每秒重新計算一次,將一組新的相依項值新增至內部快取,隨著時間推移,可能會導致記憶體問題,因為內部快取會無限期成長。使用 most-recent
逐出政策後,內部的選擇器快取只會保留最新的一組相依項及其值,以及根據這些相依項算出的實際選擇器值,如此一來就能解決記憶體問題。
目前的逐出選項有:
lru
- 當快取大小超過maxSize
時,會從快取中逐出最近最少使用的值。most-recent
- 僅保留最新的值。keep-all
(預設) - 保留快取中的所有項目,不進行逐出。
注意事項:預設的逐出政策(目前為
keep-all
)可能會在未來變更。
使用多個原子執行的交易
介紹一種進階 API,可將多個原子一起更新為單一交易。新的 useRecoilTransaction_UNSTABLE()
程式碼更簡單、更有效率且更安全。此新的程式碼最後應該會取代大多數使用 useRecoilCallback()
的情況,但是此版本僅為初始實作,具有部分限制,這些限制將在未來版本中修正。
範例
假設我們有兩個原子,positionState
和 headingState
,我們希望將它們一起更新為單一動作的一部分,其中 positionState
的新值是 positionState
和 headingState
當前值的函數。您可以使用交易達成此目的,而交易必須是純粹且無副作用的函數
const goForward = useRecoilTransaction_UNSTABLE(({get, set}) => (distance) => {
const heading = get(headingState);
const position = get(positionState);
set(positionAtom, {
x: position.x + cos(heading) * distance,
y: position.y + sin(heading) * distance,
});
});
接著,只要在事件處理常式中呼叫 goForward(distance)
,您就可以執行交易。這會依據目前的值,而不是組件呈示時的狀態,更新狀態。您也可以在交易期間讀取先前寫入的值。由於更新程式執行時不會提交任何其他更新,因此您將會看到一致的狀態儲存。
先前使用 useRecoilCallback()
的方法如下
const goForward = useRecoilCallback(({snapshot, gotoSnapshot}) => (distance) => {
const mutatedSnapshot = snapshot.map(({get, set}) => {
const heading = get(headingState);
const position = get(positionState);
set(positionState, {
x: position.x + cos(heading) * distance,
y: position.y + sin(heading) * distance,
});
});
gotoSnapshot(mutatedSnapshot);
});
這有下列缺點
- 管理快照的所有概括性會造成效能負擔。
- 錯誤發生的機率較高:快照可能會保留並用於未來。由於快照包含全套 Recoil 狀態,而不僅僅是變更組,它可能會意外還原在建立和提交快照之間發生的變更。
縮減範例
您也可以使用此程式碼建立執行多個原子動作的縮減模式
const reducer = useRecoilTransaction_UNSTABLE(({get, set}) => action => {
switch(action.type) {
case 'goForward':
const heading = get(headingState);
set(positionState, position => {
x: position.x + cos(heading) * action.distance,
y: position.y + sin(heading) * action.distance,
});
break;
case 'turn':
set(headingState, action.heading);
break;
}
});