Snapshot
ある時点における、すべての Recoil state にアクセスするためのインターフェース
デバッグ用途やデータの永続化などのアプリケーション全体に作用する Hooks で標準的に採用されている
Snapshot という名前の通り、ある時点での状態をコピーしたもので、通常の Snapshot は read-only である(後述)
Snapshot インターフェースは次の4つのメソッドを提供する
getLoadable: ある Recoil state の value を Loadable として取得する getPromise: ある Recoil state の value を Promise として取得する
map: Recoil state を同期的に変更し、変更後の Snapshot を返す(後述)
asyncMap: Recoil state を非同期的に変更し、変更後の Snapshot を Promise で返す(後述)
map メソッドについて
まず、単に Snapshot と呼ぶ場合、それは read-only な Snapshot を意味する
Snapshot を通じてアプリケーションの状態を直接変化させることはできない
しかし、「Snapshot のコピー」を作って、コピーに変更を加えたのち、アプリケーションに設定することはできる
Snapshot に変更を加えるには、 MutableSnapshot という特別な Snapshot を用いる必要がある
MutableSnapshot には Recoil state に value を書き込むための set と reset というメソッドが追加されている
MutableSnapshot は map メソッドのコールバックパラメータとして与えられる
コールバックではあるが、同期的に実行される(非同期ではない!)
map メソッドの戻り値として、変更後の Snapshot (read-only な Snapshot)が得られる
誤解のないように言っておくと、Atom や Selector の value は つねに Immutable である
asyncMap メソッドについて
変更を加える処理が非同期になってしまう場合、 asyncMap を使うと、コールバック関数を Promsied にできる
「あなたがコールバックとして与える関数」は Promised だが、 set/reset そのものは同期的に実行される
ゆえに、実装上はほとんど map と差がない
戻り値は Promise<Snapshot> である
currentTree と nextTree
Recoil は currentTree と nextTree という2つの Data-Flow Graph (有向グラフ) を持っている
これはレンダリングにおけるダブルバッファリングに似ているかも知れない
currentTree は、既に確定された状態であり、それ以上は更新されない
nextTree は、現在のバッチが終了するまで、どんどん更新される
現在のバッチが終了したら nextTree を元にアプリケーションが再描画され、 nextTree = currentTree する
そのあと nextTree = null され、次のバッチが終了したときにまだ null であれば再描画はスキップされる
データを読み取るために与えられる Snapshot は currentTree から作られる
データを書き込む対象は nextTree になる