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

selectorFamily(options)

読み取り専用のRecoilValueReadOnlyまたは書き込み可能なRecoilStateセレクターを返す関数を返します。

selectorFamilyは、selectorと似ていますが、selectorgetおよびsetコールバックに関数を渡すことができる強力なパターンです。 selectorFamily()ユーティリティは、ユーザー定義のパラメータで呼び出すことができ、セレクタを返す関数を返します。それぞれ一意のパラメータ値は、同じメモ化されたセレクタインスタンスを返します。


読み取り専用セレクターファミリー

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

get: P => ({
get: GetRecoilValue
getCallback: GetCallback<T>,
}) =>
T | Promise<T> | Loadable<T> | WrappedValue<T> | RecoilValue<T>,

dangerouslyAllowMutability?: boolean,
}): P => RecoilValueReadOnly<T>

書き込み可能セレクターファミリー

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

get: P => ({
get: GetRecoilValue
getCallback: GetCallback<T>,
}) =>
T | Promise<T> | Loadable<T> | WrappedValue<T> | RecoilValue<T>,

set: P => (
{
get: GetRecoilValue,
set: SetRecoilValue,
reset: ResetRecoilValue,
},
newValue: T | DefaultValue,
) => void,

dangerouslyAllowMutability?: boolean,

cachePolicy_UNSTABLE?: CachePolicy,
}): P => RecoilState<T>

ここで

type ValueOrUpdater<T> =  T | DefaultValue | ((prevValue: T) => T | DefaultValue);

type GetRecoilValue = <T>(RecoilValue<T>) => T;
type SetRecoilValue = <T>(RecoilState<T>, ValueOrUpdater<T>) => void;
type ResetRecoilValue = <T>(RecoilState<T>) => void;

type GetCallback<T> =
<Args, Return>(
callback: ({node: RecoilState<T>, ...CallbackInterface}) => (...Args) => Return,
) => (...Args) => Return;

type CachePolicy =
| {eviction: 'lru', maxSize: number}
| {eviction: 'keep-all'}
| {eviction: 'most-recent'};
  • key - アトムを内部的に識別するために使用される一意の文字列。この文字列は、アプリケーション全体で他のアトムおよびセレクタに対して一意である必要があります。
  • get - セレクタの値を返す名前付きコールバックのオブジェクトを渡される関数。これは、selector()インターフェースと同じです。これは、セレクターファミリ関数を呼び出すことからパラメータを渡される関数によってラップされます。
  • set? - オプションの関数。指定すると、書き込み可能なセレクターが生成されます。 selector()インターフェースと同じ名前付きコールバックのオブジェクトを受け取る関数である必要があります。これは、セレクターファミリ関数を呼び出すことからパラメータを取得する別の関数によって再びラップされます。
  • cachePolicy_UNSTABLE - ファミリーを構成する**個々のセレクタ**の内部セレクタキャッシュの動作を定義します(ファミリーに格納されるセレクタの数を制御するものではありません)。依存関係が頻繁に変化するセレクタを持つアプリケーションのメモリフットプリントを制御するのに役立ちます。
    • eviction - lrumaxSizeを設定する必要があります)、keep-all(デフォルト)、またはmost-recentに設定できます。 lruキャッシュは、キャッシュのサイズがmaxSizeを超えると、セレクタキャッシュから最も最近使用されていない値を削除します。 keep-allポリシーは、すべてのセレクタの依存関係とその値がセレクタキャッシュに無期限に保存されることを意味します。 most-recentポリシーは、サイズ1のキャッシュを使用し、最後に保存された依存関係とその値のセットのみを保持します。
    • lruと一緒に使用されるmaxSizeプロパティは、ファミリー自体の最大サイズを制御するのではなく、ファミリーを構成する個々のセレクタで使用される削除ポリシーのみを制御することに注意してください。
    • キャッシュは、すべての依存関係とその値を含むキーに基づいてセレクタの値を格納することに注意してください。これは、内部セレクタキャッシュのサイズが、セレクタ値のサイズとすべての依存関係の一意の値の数に依存することを意味します。
    • デフォルトの削除ポリシー(現在keep-all)は将来変更される可能性があることに注意してください。

selectorFamily()は、基本的にパラメータからセレクタへのマップを提供します。アトムファミリーには単一のキーを提供するだけで、基になる各セレクタの一意のキーが生成されます。

パラメータタイプ

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

ファミリーParameterとして使用できるタイプには制限があります。それらは異なる呼び出しサイトで生成される可能性があり、同等のパラメータが同じ基になるセレクタを参照するようにしたいと考えています。したがって、パラメータは値の等価性を使用して比較され、シリアル化可能である必要があります。パラメータで関数やPromiseなどの可変オブジェクトを使用すると問題が発生します。シリアル化可能にするには、次のいずれかである必要があります。

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

const myNumberState = atom({
key: 'MyNumber',
default: 2,
});

const myMultipliedState = selectorFamily({
key: 'MyMultipliedNumber',
get: (multiplier) => ({get}) => {
return get(myNumberState) * multiplier;
},

// optional set
set: (multiplier) => ({set}, newValue) => {
set(myNumberState, newValue / multiplier);
},
});

function MyComponent() {
// defaults to 2
const number = useRecoilValue(myNumberState);

// defaults to 200
const multipliedNumber = useRecoilValue(myMultipliedState(100));

return <div>...</div>;
}

非同期クエリ例

セレクターファミリーは、クエリにパラメータを渡すためにも役立ちます。このようにクエリを抽象化するためにセレクターを使用する場合でも、与えられた入力と依存関係値のセットに対して常に同じ結果を返す「純粋な」関数である必要があることに注意してください。詳細な例については、このガイドを参照してください。

const myDataQuery = selectorFamily({
key: 'MyDataQuery',
get: (queryParameters) => async ({get}) => {
const response = await asyncDataRequest(queryParameters);
if (response.error) {
throw response.error;
}
return response.data;
},
});

function MyComponent() {
const data = useRecoilValue(myDataQuery({userID: 132}));
return <div>...</div>;
}

分割代入の例

const formState = atom({
key: 'formState',
default: {
field1: "1",
field2: "2",
field3: "3",
},
});

const formFieldState = selectorFamily({
key: 'FormField',
get: field => ({get}) => get(formState)[field],
set: field => ({set}, newValue) =>
set(formState, prevState => ({...prevState, [field]: newValue})),
});

const Component1 = () => {
const [value, onChange] = useRecoilState(formFieldState('field1'));
return (
<>
<input value={value} onChange={onChange} />
<Component2 />
</>
);
}

const Component2 = () => {
const [value, onChange] = useRecoilState(formFieldState('field2'));
return (
<input value={value} onChange={onChange} />
);
}

キャッシュポリシーの設定

cachePolicy_UNSTABLEプロパティを使用すると、ファミリーを構成する**個々のセレクタ**のキャッシュ動作を設定できます。このプロパティは、依存関係が頻繁に変化するセレクタが多数あるアプリケーションのメモリを削減するのに役立ちます。セレクタキャッシュポリシー設定のドキュメントを参照してください。