Recoil を React Suspense と使う
recoil はデフォルトで React.suspense
をサポートします。
そのおかげで非同期なデータを非常にシンプルに扱うことができます。
今回は使用例を参考にどんな風に動作するかを確認します。
Recoil atom x React Suspense の使い方
使用例
testState
は非同期な値をもつatom
です。
TestChild
コンポーネントはtestState
を読み込んで使用と更新をしています。
Test
コンポーネントはtestState
コンポーネントの親コンポーネントです。TestChild
をSuspense
で囲んで利用しています。
import { atom } from 'recoil';
const testState = atom<number>({
key: 'test',
default: new Promise((resolve) => {
setTimeout(() => {
resolve(100);
}, 5 * 1000);
}),
});
export { testState };
import * as React from 'react';
import { RecoilRoot, useRecoilState } from 'recoil';
import { testState } from '@src/stores/test';
function TestChild() {
const [test, setTest] = useRecoilState(testState);
return (
<div>
<h4>Test Child</h4>
<h5>current value: {test}</h5>
<button type='button' onClick={() => setTest((currentTest) => currentTest + 1)}>
increment
</button>
</div>
);
}
export default function Test() {
return (
<div>
<h4>Test</h4>
<RecoilRoot>
<React.Suspense fallback={<div>Now Loading...</div>}>
<TestChild />
</React.Suspense>
</RecoilRoot>
</div>
);
}
動作の解説
上記のコードは下記のような動作となります。
-
Promise
が未解決の間はReact.Suspense
で設定したフォールバックコンポーネントが表示される。 -
Promise
が解決されると、TestChild
は再レンダリングされる。その際useRecoilState
からはtest
が解決された同期的な値として返される。 - 初期値が解決する前に新しい値がセットされると、フォールバックは終わり新しい値で再レンダリングされる。
-
Promise
でエラーが発生した場合は、ErrorBoundary
までフォールバックされる。
なんでそんな動作になるのか?
recoil 内では初期値がPromise
の場合にuseRecoilValue
などで呼び出されると状態のよって以下のような挙動となることで上記機能を実現している。
1. 状態が未解決なPromise
の場合:useRecoilValue
はPromise
をthrow
する。
throw
されたPromise
はSuspense
でキャッチされフォールバックコンポーネントが描写される。Promise
が解決されると再描写される。
また、Promise
が未解決であっても新しい同期的な値をatom
にセットすると、Recoil
が初期値のPromise
を解決してくれる。
2. 状態が解決済なPromise
の場合:useRecoilValue
は解決した同期的な値を返す
3. 状態がReject
されたPromise
の場合:useRecoilValue
はエラーをthrow
エラーはErrorBoundary
でキャッチされる。
注意点
Recoil のatom
は初期値としてのみPromise
を受け取ることができます。
これで何が嬉しいのか
コンポーネントから状態を減らせる
今まで非同期データを扱う場合、ローディング中かどうかで UI を切り替えるためにisLoading
みたいな状態が必要だったが、それが不要になる。
コンポーネント内で非同期を意識しなくていい
useRecoilValue
は解決した値を同期的に返すのでコンポーネント内では非同期を意識する必要がない。
Recoil と React Suspense を使ったサンプル
Recoil と React Suspense で Firebase Authentication の状態を管理するサンプルを作成しました。
また状態管理ライブラリのjotai
も同じようにSuspense
に対応しています。
Discussion