メインコンテンツにスキップ

atomFamily(options)

書き込み可能な RecoilState アトムを返す関数を返します。


function atomFamily<T, P: Parameter>({
key: string,

default?:
| T
| Promise<T>
| Loadable<T>
| WrappedValue<T>
| RecoilValue<T>
| (P => T | Promise<T> | Loadable<T> | WrappedValue<T> | RecoilValue<T>),

effects?:
| $ReadOnlyArray<AtomEffect<T>>
| (P => $ReadOnlyArray<AtomEffect<T>>),

dangerouslyAllowMutability?: boolean,
}): P => RecoilState<T>
  • key - アトムを内部的に識別するために使用される一意の文字列。この文字列は、アプリケーション全体のアトムやセレクタに対して一意である必要があります。
  • default - アトムの初期値。アトムと同様に、値を直接指定することも、PromiseLoadable、ラップされた値、またはデフォルト値を表す別のアトム/セレクタを指定することもできます。アトムファミリは、パラメータを渡されてそのファミリメンバーのデフォルトを返す関数にすることもできます。指定しない場合、アトムは保留中の状態で開始され、Suspense をトリガーします。
  • effects - アトムエフェクトのオプションの配列、またはファミリパラメータに基づいて配列を取得するためのコールバック。
  • dangerouslyAllowMutability - Recoil は、アトムの状態変更に依存して、アトムを使用するコンポーネントに再レンダリングを通知するタイミングを決定します。アトムの値が変更された場合、これをバイパスして、サブスクライブしているコンポーネントに適切に通知することなく状態が変更される可能性があります。これを防ぐために、保存されているすべての値は凍結されています。場合によっては、このオプションを使用してこれをオーバーライドすることが望ましい場合があります。

atom は、Recoil の状態の一部を表します。アトムは、アプリによって <RecoilRoot> ごとに作成および登録されます。しかし、状態がグローバルでない場合はどうでしょうか?状態がコントロールの特定のインスタンス、または特定の要素に関連付けられている場合はどうでしょうか?たとえば、アプリが UI プロトタイピングツールであり、ユーザーが要素を動的に追加でき、各要素に位置などの状態がある場合です。理想的には、各要素に独自の状態のアトムが必要です。これをメモ化パターンを使用して自分で実装できます。しかし、RecoilatomFamily() ユーティリティでこのパターンを提供しています。アトムファミリは、アトムのコレクションを表します。 atomFamily() を呼び出すと、渡されたパラメータに基づいて RecoilState アトムを提供する関数が返されます。

パラメータタイプ

type Primitive = void | null | boolean | number | string;
interface HasToJSON {
toJSON(): Parameter;
}
type Parameter =
| Primitive
| HasToJSON
| $ReadOnlyArray<Parameter>
| $ReadOnly<{[string]: Parameter}>
| $ReadOnlySet<Parameter>
| $ReadOnlyMap<Parameter, Parameter>;

atomFamily() は、基本的にパラメータからアトムへのマップを提供します。アトムファミリには単一のキーを提供するだけで、基になる各アトムの一意のキーが生成されます。これらのアトムキーは永続化に使用できるため、アプリケーションの実行全体で安定している必要があります。

ファミリ Parameter として使用できる型には制限があります。これらは異なる呼び出しサイトで生成される可能性があり、同等のパラメータが同じ基になるアトムを参照するようにしたいと考えています。したがって、パラメータは値の等価性を使用して比較され、シリアライズ可能である必要があります。シリアライズ可能にするには、次のいずれかである必要があります

  • プリミティブ値
  • シリアライズ可能な値の配列、オブジェクト、Map、または Set
  • JSON.stringify() と同様に、シリアライズ可能な値を返す toJSON() メソッドを含む

const elementPositionStateFamily = atomFamily({
key: 'ElementPosition',
default: [0, 0],
});

function ElementListItem({elementID}) {
const position = useRecoilValue(elementPositionStateFamily(elementID));
return (
<div>
Element: {elementID}
Position: {position}
</div>
);
}

ファミリのデフォルト

atomFamily() は、単純な atom() とほぼ同じオプションを取ります。ただし、デフォルト値をパラメータ化することもできます。つまり、パラメータ値を受け取り、実際のデフォルト値を返す関数を指定できます。例えば

const myAtomFamily = atomFamily({
key: ‘MyAtom’,
default: param => defaultBasedOnParam(param),
});

他の状態に基づく動的なデフォルト値の場合は、パラメータ値にもアクセスできる selectorFamily() を使用します。 atomFamily() のデフォルトに selector() を使用しないでください。重複キーが生成されるためです。

const myAtomFamily = atomFamily({
key: ‘MyAtom’,
default: selectorFamily({
key: 'MyAtom/Default',
get: param => ({get}) => {
const otherAtomValue = get(otherState);
return computeDefaultUsingParam(otherAtomValue, param);
},
}),
});

サブスクリプション

すべての要素の状態のマップを持つ単一のアトムを格納しようとするのではなく、各要素に個別のアトムを使用するこのパターンの利点の 1 つは、すべてが独自の個別のサブスクリプションを維持することです。そのため、1 つの要素の値を更新すると、そのアトムのみにサブスクライブしている React コンポーネントのみが更新されます。

スコープ付きアトム

他のプロパティ、React コンテキスト、または状態の一部によってアトム状態を「スコープ」したい場合があります。例えば

const viewWidthForPaneState = atomFamily<number, PaneID>({
key: 'ViewWidthForPane',
default: 42,
});

function PaneView() {
const paneID = useContext(PaneIDContext);
const viewWidth = useRecoilValue(viewWidthForPaneState(paneID));
...
}

他の Recoil 状態によってスコープを設定し、すべての呼び出しサイトでスコープパラメータを検索することを避けたい場合は、ラッパー selector() を使用すると便利な場合があります

const viewWidthState = selector({
key: 'ViewWidth',
get: ({get}) => viewWidthForPane(get(currentPaneState)),
set: ({get, set}, newValue) => set(viewWidthForPane(get(currentPaneState)), newValue),
});

function PaneView() {
const viewWidth = useRecoilValue(viewWidthState);
...
}

永続性

永続性オブザーバーと アトムエフェクト は、使用されるパラメータ値のシリアライズに基づく一意のキーを持つ別個のアトムとして、各パラメータ値の状態を同期します。したがって、シリアライズ可能なパラメータであることが重要です。カスタムクラスや関数は許可されていません。