跳至主要内容

useRecoilTransaction_UNSTABLE(callback, deps)

创建一个事务回调函数,该函数可用于以安全、轻松且高效的方式原子地更新多个原子。提供一个事务的回调函数,该函数是一个纯函数,可以get()set()多个原子。事务类似于设置 Recoil 状态的“更新器”形式,但可以在多个原子之间进行操作。在同一事务中,写操作对后续读取可见。

除了事务之外,此钩子还可以用于:

  • 实现 reducer 模式以对多个原子执行操作。
  • 动态更新原子,在渲染时我们可能不知道要更新哪个原子或选择器,因此无法使用useSetRecoilState()
  • 预取渲染前的數據。

interface TransactionInterface {
get: <T>(RecoilValue<T>) => T;
set: <T>(RecoilState<T>, (T => T) | T) => void;
reset: <T>(RecoilState<T>) => void;
}

function useRecoilTransaction_UNSTABLE<Args>(
callback: TransactionInterface => (...Args) => void,
deps?: $ReadOnlyArray<mixed>,
): (...Args) => void
  • callback - 用户回调函数,带有提供事务接口的包装函数。此函数必须是纯函数,没有任何副作用。
  • deps - 用于记忆回调函数的可选依赖项集。与useCallback()类似,生成的交易回调函数默认情况下不会被记忆,并且每次渲染都会生成一个新的函数。你可以传递一个空数组来始终返回相同的函数实例。如果在deps数组中传递值,如果任何依赖项的引用相等性发生变化,将使用一个新的函数。这些值然后可以在回调函数主体内部使用,而不会变得陈旧。(参见useCallback)你可以更新 eslint以帮助确保此功能被正确使用。

事务接口

  • get - 获取请求的 Recoil 状态的当前值,反映在事务中早先执行的任何写入操作。目前仅支持同步原子。
  • set - 设置原子的值。你可以直接提供新值,或者提供一个更新器函数,该函数返回新值并以当前值为参数。当前值代表当前事务中所有其他待处理状态更改的日期。
  • reset - 将原子的值重置为其默认值。

事务示例

假设我们有两个原子,positionStateheadingState,并且我们想将它们一起更新为单个操作的一部分,其中positionState的新值是当前positionStateheadingState值的一个函数。

const goForward = useRecoilTransaction_UNSTABLE(({get, set}) => (distance) => {
const heading = get(headingState);
const position = get(positionState);
set(positionState, {
x: position.x + cos(heading) * distance,
y: position.y + sin(heading) * distance,
});
});

然后,你可以通过在事件处理程序中调用goForward(distance)来执行事务。这将根据当前值更新状态,而不是组件渲染时的状态。

你也可以在事务期间读取先前写入的值。由于在更新器执行期间不会进行其他更新,因此你将看到一致的状态存储。

const moveInAnL = useRecoilTransaction_UNSTABLE(({get, set}) => () => {
// Move Forward 1
const heading = get(headingState);
const position = get(positionState);
set(positionState, {
x: position.x + cos(heading),
y: position.y + sin(heading),
});

// Turn Right
set(headingState, heading => heading + 90);

// Move Forward 1
const newHeading = get(headingState);
const newPosition = get(positionState);
set(positionState, {
x: newPosition.x + cos(newHeading),
y: newPosition.y + sin(newHeading),
});
});

Reducer 示例

此钩子也适用于实现 reducer 模式,以便对多个原子执行操作。

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;
}
});

当前限制和未来愿景

  • 事务目前仅支持原子,尚不支持选择器。未来可以添加此支持。
  • 具有作为选择器的默认值的原子目前也不支持。
  • 读取的原子必须具有同步值。如果它处于错误状态或异步挂起状态,则事务将抛出错误。可以通过在依赖项挂起时中止事务,并在依赖项可用时重新启动事务来支持挂起的依赖项。这与选择器get()的实现方式一致。
  • 事务没有返回值。如果我们想在事务完成时获得一些通知,或者使用事务请求缓慢的数据,或者从事件处理程序请求数据,那么我们可以让事务返回一个指向返回值的Promise
  • 事务必须是同步的。有一个提议允许异步事务。用户可以提供一个async事务回调函数,该函数可以使用await。然而,所有设置的原子更新将不会被应用,直到事务返回的Promise完全解析。
  • 事务不能有任何副作用。如果你需要副作用,请改用useRecoilCallback()