教程 > Recoil.js > Recoil 手册 阅读:49

useRecoilTransaction_UNSTABLE(callback, deps)

useRecoilTransaction() 创建一个事务回调,可用于以安全、简单和高效的方式自动更新多个原子。 为事务提供回调作为可以get()set()多个原子的纯函数。 事务类似于设置 Recoil 状态的“更新器”形式,但可以在多个原子上操作。 写入对来自同一事务中的后续读取是可见的。

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

  • 实现 reducer 模式以对多个 atom 执行操作。
  • 动态更新一个原子,我们在渲染时可能不知道我们想要更新哪个原子或选择器,所以我们不能使用 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 数组中传递值,则如果任何 dep 的引用相等性发生更改,将使用一个新函数。 然后可以在回调的主体中使用这些值而不会过时。 (请参阅 useCallback)我们可以更新 eslint 以帮助确保正确使用它。

Transaction 接口:

  • get - 获取请求的 Recoil 状态的当前值,反映事务中较早执行的任何写入。 目前仅支持同步原子。
  • set - 设置原子的值。 我们可以直接提供新值,也可以提供返回新值并将当前值作为参数的更新函数。 当前值表示当前事务中迄今为止的所有其他未决状态更改。
  • reset - 将 atom 的值重置为其默认值。

Transaction 示例

假设我们有两个原子,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 模式以在多个 atom 上执行操作也很有用:

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 到一个返回值。
  • 事务必须是同步的。有一个允许异步事务的提议。用户可以提供一个可以使用 await 的异步事务回调函数。但是,在事务返回的 Promise 完全解决之前,不会应用所有集合的原子更新。
  • 事务不得有任何副作用。

查看笔记

扫码一下
查看教程更方便