jotai v2.2.0 で入った atomWithDefault の破壊的変更による影響と対策
INDEX
jotai v2.2.0 で atomWithDefault に破壊的変更が入った
// suppose we have this
const asyncAtom = atom(() => Promise.resolve(1));
const countAtom = atomWithDefault((get) => get(asyncAtom));
// and in component
const setCount = useSetAtom(countAtom);
// previously,
setCount((c) => c + 1); // it worked, but it will no longer work
// instead, you need to do this
setCount((countPromise) => countPromise.then((c) => c + 1));
引用:https://github.com/pmndrs/jotai/releases/tag/v2.2.0
これまで非同期 atom(async atom)から atomWithDefault で派生した atom を更新するには同期なインターフェースとなっていたが、非同期 atom の場合は Promise を返すようになりました。
非同期 atom を更新すると Supsense の Suspend が発生するようになる
これまでは非同期 atom から atomWithDefault で作成した atom を更新時には、Suspend は発生しませんでした。
今回の変更によって atomWithDefault で作成した非同期 atom は更新時に Suspend が僅かながらでも発生するケースがあり、更新時に Suspense で囲っている境界でちらつきが発生するようになります。
Suspend への対策
Discussion 上では非同期 atom の Suspend への対策として 3 つの例が例示されています。
※2 番目の例は atomWithDefault を使わない例になるので割愛します
unstable_unwrap
unstable がついていますが将来的に外れる予定の unwrap 関数を使用して非同期 atom を同期 atom に変換します。
この際に注意しないといけないのが、useAtom から返される atom の値が undefined が含まれるようになります。
const asyncAtom = atom(Promise.resolve(1));
const asyncCountAtom = atomWithDefault((get) => get(asyncAtom));
const countAtom = unstable_unwrap(asyncCountAtom);
function Component() {
const [count, setCount] = useAtom(countAtom);
// ^? const count: number | undefined
}
undefined を回避するには、unwrap 関数の第二引数にフォールバックを指定します。
const asyncAtom = atom(Promise.resolve(1));
const asyncCountAtom = atomWithDefault((get) => get(asyncAtom));
const countAtom = unstable_unwrap(asyncCountAtom, (prev) => prev ?? 1);
function Component() {
const [count, setCount] = useAtom(countAtom);
// ^? const count: number
}
初期値が外部リソースではない時はこのケースが適していそうです。
useAtom のdelay オプション
const [count, setCount] = useAtom(countAtom, { delay: 100 });
この辺りが一番手軽に導入できそうですが、遅らせる時間をどれくらいにするのかは悩みどころです。
その他:React の useTransition
const [, startTransition] = useTransition();
const [count, setCount] = useAtom(countAtom);
const increment = () => {
startTransition(() => {
setCount((p) => p.then((prev) => prev + 1));
});
};
Suspense の Suspend によってちらつくなら、そもそも React の機能なので React の API で対応しちゃうパターンです。
さいごに
Jotai の非同期 atom を使うことで、Render-as-you-fetch パターンを簡単に導入できるので非常に便利です。
便利な分、ライブラリのアップデートに定期的に追随していく筋力が必要だなと思う今日この頃です。
この記事を書いた人
- 2013年にアーティスに入社。システムエンジニアとしてアーティスCMSを使用したWebサイトや受託システムの構築・保守に携わる。環境構築が好き。
関連記事
最新記事
FOLLOW US
最新の情報をお届けします
- facebookでフォロー
- Twitterでフォロー
- Feedlyでフォロー