Open1
jotaiの自作ユーティリティ置き場
import { atom, type WritableAtom } from "jotai";
import { selectAtom } from "jotai/utils";
const judge = <Value>(cur: Value, prev: Value | undefined):Value => (!prev ? cur : prev);
export const atomWithStorageOnce = <Value, Args extends unknown[], Result>(
anAtom: WritableAtom<Value, Args, Result>,
) =>
atom(
(get) => get(selectAtom<Value, Value>(anAtom, judge)),
(_, set, ...update: Args) => set(anAtom, ...update),
);
atomWithStorageを使っているatomで、初回マウント時に初期値としてstorageに保存してあるatomの状態にアクセスしたいが、それ以降はそのコンポーネントが持つuseStateを使用するようにし、書き込み方向のアクセスのみを行いたい場合に使えるユーティリティ。
このユーティリティ経由でatomを使用するようにすれば、コンポーネント自身はクソデカオブジェクトのatomの変更に反応することなく、自身の状態の変更のみに反応することができる。
更にstartTransitionと併用することで、画面の更新を並列で処理できる。
judge関数を外出ししているのは、外出ししないと関数が実行毎に作成されて無限ループが発生してしまうため。
使い方
import { atomWithStorageOnce } from "@/utils";
import { atomWithStorage } from "jotai/utils";
import { type Dispatch, type SetStateAction, startTransition, useCallback, useState } from "react";
const localStorageAtom = atomWithStorage("key",atom(0));
export const useNumberState = () => {
const anAtom = atomWithStorageOnce(localStorageAtom);
const [initialValue, setValue] = useAtom(anAtom);
const [state, setState] = useState(initialValue);
const dispatch: Dispatch<SetStateAction<number>> = useCallback(
(value) => {
setState(value);
startTransition(() => setValue(value));
},
[setValue],
);
return [state, dispatch] as const;
};