跳至主要内容

useRecoilCallback(callback, deps)

这个钩子类似于 useCallback(),但它还将为你的回调提供与 Recoil 状态交互的 API。这个钩子可以用来构建一个回调函数,该回调函数可以访问 Recoil 状态的只读 Snapshot,并能够异步更新当前 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>
);
}