コアコンセプト
概要
Recoilは、アトム(共有状態)からセレクタ(純粋関数)を介してReactコンポーネントへと流れるデータフローグラフを作成できます。アトムは、コンポーネントが購読できる状態の単位です。セレクタは、この状態を同期または非同期に変換します。
アトム
アトムは状態の単位です。更新可能で購読可能です。アトムが更新されると、購読している各コンポーネントは新しい値で再レンダリングされます。実行時に作成することもできます。アトムは、Reactのローカルコンポーネントの状態の代わりに使用できます。複数のコンポーネントから同じアトムが使用されている場合、それらのコンポーネントはすべて状態を共有します。
アトムはatom
関数を使用して作成されます
const fontSizeState = atom({
key: 'fontSizeState',
default: 14,
});
アトムには一意のキーが必要です。これは、デバッグ、永続化、およびすべてのアトムのマップを表示できる特定の高度なAPIに使用されます。 2つのアトムが同じキーを持つことはエラーであるため、グローバルに一意であることを確認してください。 Reactコンポーネントの状態と同様に、デフォルト値もあります。
コンポーネントからアトムを読み書きするには、useRecoilState
というフックを使用します。 ReactのuseState
と似ていますが、状態はコンポーネント間で共有できます。
function FontButton() {
const [fontSize, setFontSize] = useRecoilState(fontSizeState);
return (
<button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}>
Click to Enlarge
</button>
);
}
ボタンをクリックすると、ボタンのフォントサイズが1ずつ増加します。しかし、他のコンポーネントも同じフォントサイズを使用できます。
function Text() {
const [fontSize, setFontSize] = useRecoilState(fontSizeState);
return <p style={{fontSize}}>This text will increase in size too.</p>;
}
セレクタ
セレクタは、アトムまたは他のセレクタを入力として受け入れる純粋関数です。これらのアップストリームのアトムまたはセレクタが更新されると、セレクタ関数が再評価されます。コンポーネントはアトムと同様にセレクタを購読でき、セレクタが変更されると再レンダリングされます。
セレクタは、状態に基づいて派生データを計算するために使用されます。最小限の状態がアトムに格納され、他のすべてがその最小限の状態の関数として効率的に計算されるため、冗長な状態を回避できます。セレクタは、どのコンポーネントがそれらを必要とし、どの状態に依存しているかを追跡するため、この関数型アプローチを非常に効率的にします。
コンポーネントの観点からは、セレクタとアトムは同じインターフェースを持ち、互いに置き換えることができます。
セレクタはselector
関数を使用して定義されます
const fontSizeLabelState = selector({
key: 'fontSizeLabelState',
get: ({get}) => {
const fontSize = get(fontSizeState);
const unit = 'px';
return `${fontSize}${unit}`;
},
});
get
プロパティは、計算される関数です。 get
引数を使用して、アトムや他のセレクタの値にアクセスできます。 別のアトムまたはセレクタにアクセスするたびに、依存関係が作成され、他のアトムまたはセレクタを更新すると、これが再計算されるようになります。
このfontSizeLabelState
の例では、セレクタには1つの依存関係があります。fontSizeState
アトムです。概念的には、fontSizeLabelState
セレクタは、fontSizeState
を入力として受け取り、フォーマットされたフォントサイズラベルを出力として返す純粋関数のように動作します。
セレクタはuseRecoilValue()
を使用して読み取ることができます。これは、アトムまたはセレクタを引数として受け取り、対応する値を返します。 fontSizeLabelState
セレクタは書き込み可能ではないため、useRecoilState()
は使用しません(書き込み可能なセレクタの詳細については、セレクタAPIリファレンスを参照してください)
function FontButton() {
const [fontSize, setFontSize] = useRecoilState(fontSizeState);
const fontSizeLabel = useRecoilValue(fontSizeLabelState);
return (
<>
<div>Current font size: {fontSizeLabel}</div>
<button onClick={() => setFontSize(fontSize + 1)} style={{fontSize}}>
Click to Enlarge
</button>
</>
);
}
ボタンをクリックすると、2つのことが行われます。ボタンのフォントサイズが増加し、現在のフォントサイズを反映するようにフォントサイズラベルが更新されます。