useRecoilTransaction_UNSTABLE(callback, deps)
複数のアトムを安全、簡単、かつ効率的にアトミックに更新するために使用できるトランザクションコールバックを作成します。トランザクションのコールバックを、複数のアトムを`get()`または`set()`できる純粋関数として提供します。トランザクションは、Recoil状態を設定する「アップデーター」形式に似ていますが、複数のアトムを操作できます。書き込みは、同じトランザクション内からの後続の読み取りに対して可視です。
トランザクションに加えて、このフックは次の場合にも役立ちます。
- 複数のアトムに対してアクションを実行するためのリデューサーパターンを実装する。
- どのアトムまたはセレクターを更新する必要があるかをレンダリング時に把握できない場合にアトムを動的に更新するため、
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
- トランザクションで wcześniej 実行された書き込みを反映して、要求されたRecoil状態の現在の値を取得します。これは現在、同期アトムのみをサポートしています。set
- アトムの値を設定します。新しい値を直接提供するか、新しい値を返し、現在の値をパラメーターとして取るアップデーター関数を指定できます。現在の値は、現在のトランザクションにおける現在までの他のすべての保留中の状態変更を表します。reset
- アトムの値をデフォルトにリセットします。
トランザクションの例
`positionState`と`headingState`の2つのアトムがあり、単一のアクションの一部として一緒に更新したいとします。ここで、`positionState`の新しい値は、`positionState`と`headingState`の*両方*の現在の値の関数です。
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),
});
});
リデューサーの例
このフックは、複数のアトムに対してアクションを実行するためのリデューサーパターンを実装する場合にも役立ちます。
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`を使用できる`async`トランザクションコールバック関数を指定できます。ただし、すべてのセットのアトミック更新は、トランザクションによって返された`Promise`が完全に解決されるまで適用されません。
- トランザクションに副作用があってはなりません。副作用が必要な場合は、代わりに
useRecoilCallback()
を使用してください。