略過前往主要內容

useRecoilCallback(callback, deps)

此掛勾類似於 useCallback(),但也會為您的回呼函式提供可與 Recoil 狀態搭配使用的 API。此掛勾可用於建立可以存取 Recoil 狀態唯讀 快照 的回呼函式,並可以在非同步更新目前的 Recoil 狀態。

使用此掛勾的一些動機可能包括

  • 非同步讀取 Recoil 狀態,而不用讓 React 元件訂閱,系統如果更新原子或選擇器就能重新渲染。
  • 將昂貴的查詢延後到您不想在渲染階段執行的非同步動作。
  • 執行副作用,同時也可以讀取或寫入 Recoil 狀態。
  • 動態更新原子或選擇器,但是我們在渲染階段可能不知道我們想要更新哪個原子或選擇器,所以不能使用 useSetRecoilState()
  • 在渲染之前 預先提取 資料。

type CallbackInterface = {
snapshot: Snapshot,
gotoSnapshot: Snapshot => void,
set: <T>(RecoilState<T>, (T => T) | T) => void,
reset: <T>(RecoilState<T>) => void,
refresh: <T>(RecoilValue<T>) => void,
transact_UNSTABLE: ((TransactionInterface) => void) => void,
};

function useRecoilCallback<Args, ReturnValue>(
callback: CallbackInterface => (...Args) => ReturnValue,
deps?: $ReadOnlyArray<mixed>,
): (...Args) => ReturnValue
  • callback - 使用者回呼函式與包裝函式的搭配,提供回呼介面。用於變更狀態的回呼函式將加入佇列,使用非同步方式更新目前的 Recoil 狀態。包裝函式的類型簽章與回傳的回呼函式簽章相符。
  • deps - 可選,用於記住回呼的相依項集合。例如透過 useCallback(),產生的回呼預設不會進行記憶,且每次渲染會產生新的函式。你可以傳遞一個空陣列,來總是傳回相同的函式實體。如果你傳遞 deps 陣列中的值,則在任何相依項的參考相等性變更時會使用新的函式。之後,你可以從回呼主體內部使用這些值,而不用擔心這些值已過期。(請參閱 useCallback)你可以 更新 eslint,以協助確保正確使用它。

回呼介面

  • snapshot - Snapshot 在存取快照時,會提供靜態的 Recoil 原子狀態。雖然原子值不變,但非同步選擇器可能會解析。快照會在同步或非同步回呼持續時間內保留,但如果你將它儲存在範圍以外並使用,則你需要 明確保留它
  • gotoSnapshot - 排隊更新全域狀態,以符合提供的 Snapshot
  • set - 排隊設定原子或選擇器的值。與其他地方一樣,你可以直接提供新值或提供一個更新器函式,該函式傳回新值,並將目前值作為參數。目前值代表目前交易中先前所有排隊的狀態變更。
  • reset - 將原子或選擇器的值重設為預設值。
  • refresh - 更新選擇器快取。
  • transact_UNSTABLE - 執行交易。請參閱 useRecoilTransaction_UNSTABLE() 文件

注意:回呼介面可以根據最佳化情況,依需求延遲計算屬性,以避免系統負擔。因此你不應該透過散佈運算子傳遞回呼介面,而應該明確地取消參照屬性,或傳遞整個代理物件。

延遲讀取範例

此範例使用 useRecoilCallback() 延遲讀取狀態,而不會訂閱組件在狀態變更時重新渲染。

import {atom, useRecoilCallback} from 'recoil';

const itemsInCart = atom({
key: 'itemsInCart',
default: 0,
});

function CartInfoDebug() {
const logCartItems = useRecoilCallback(({snapshot}) => async () => {
const numItemsInCart = await snapshot.getPromise(itemsInCart);
console.log('Items in cart: ', numItemsInCart);
}, []);

return (
<div>
<button onClick={logCartItems}>Log Cart Items</button>
</div>
);
}