diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-01 10:16:35 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-01 10:16:38 +0900 |
| commit | a07dada0c9ba80976692ee14e256da0a2d6b0112 (patch) | |
| tree | 7de73126b4e69ed3e2128e19da2eca56fe4f9e68 /src/client/atoms/utils.ts | |
| parent | 081498168fe25b377f4675637c57a08e4e399f95 (diff) | |
| download | kioku-a07dada0c9ba80976692ee14e256da0a2d6b0112.tar.gz kioku-a07dada0c9ba80976692ee14e256da0a2d6b0112.tar.zst kioku-a07dada0c9ba80976692ee14e256da0a2d6b0112.zip | |
refactor(atoms): migrate to jotai-tanstack-query from custom reloadable atoms
Replace custom createReloadableAtom/createReloadableAtomFamily with
atomWithSuspenseQuery from jotai-tanstack-query, leveraging TanStack
Query's built-in caching, invalidation, and Suspense support.
- Add @tanstack/query-core and jotai-tanstack-query dependencies
- Create shared QueryClient instance (src/client/queryClient.ts)
- Migrate all data atoms (decks, cards, study, noteTypes) to atomWithSuspenseQuery
- Update page components to use .data destructuring and queryClient.invalidateQueries()
- Update all test files to use QueryClient for data hydration
- Remove src/client/atoms/utils.ts (no longer needed)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/client/atoms/utils.ts')
| -rw-r--r-- | src/client/atoms/utils.ts | 81 |
1 files changed, 0 insertions, 81 deletions
diff --git a/src/client/atoms/utils.ts b/src/client/atoms/utils.ts deleted file mode 100644 index e7af288..0000000 --- a/src/client/atoms/utils.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { atom, type Getter, type WritableAtom } from "jotai"; - -// Symbol to identify reload action -const RELOAD = Symbol("reload"); - -/** - * A WritableAtom that returns T (or Promise<T> before hydration) and accepts - * an optional T value for hydration, or undefined to trigger reload. - */ -export type ReloadableAtom<T> = WritableAtom<T | Promise<T>, [T?], void>; - -/** - * Creates an async atom that can be reloaded by calling its setter. - * Read the atom to get the data (suspends while loading). - * Set the atom with no args to trigger a reload. - * Set the atom with a value to hydrate (useful for testing). - */ -export function createReloadableAtom<T>( - getter: (get: Getter) => Promise<T>, -): ReloadableAtom<T> { - const refetchKeyAtom = atom(0); - // Stores hydrated value - undefined means not hydrated - const hydratedValueAtom = atom<{ value: T } | undefined>(undefined); - - return atom( - // Not using async here - returns T synchronously when hydrated, Promise<T> when fetching - (get): T | Promise<T> => { - // Check for hydrated value first (sync path - avoids Suspense) - const hydrated = get(hydratedValueAtom); - if (hydrated !== undefined) { - return hydrated.value; - } - // Async path - will trigger Suspense - get(refetchKeyAtom); - return getter(get); - }, - (_get, set, action?: T | typeof RELOAD) => { - if (action === undefined || action === RELOAD) { - // Trigger reload: clear hydrated value and bump refetch key - set(hydratedValueAtom, undefined); - set(refetchKeyAtom, (k) => k + 1); - } else { - // Hydrate with value - set(hydratedValueAtom, { value: action }); - } - }, - ); -} - -// Track all atom family caches for test cleanup -const atomFamilyCaches: Map<unknown, unknown>[] = []; - -/** - * Creates a reloadable atom family for parameterized async data. - * Each unique parameter gets its own cached atom with reload capability. - */ -export function createReloadableAtomFamily<T, P extends string | number>( - getter: (param: P, get: Getter) => Promise<T>, -): (param: P) => ReloadableAtom<T> { - const cache = new Map<P, ReloadableAtom<T>>(); - atomFamilyCaches.push(cache); - - return (param: P): ReloadableAtom<T> => { - let reloadableAtom = cache.get(param); - if (!reloadableAtom) { - reloadableAtom = createReloadableAtom((get) => getter(param, get)); - cache.set(param, reloadableAtom); - } - return reloadableAtom; - }; -} - -/** - * Clears all atom family caches. Call this in test beforeEach/afterEach - * to ensure tests don't share cached atoms. - */ -export function clearAtomFamilyCaches() { - for (const cache of atomFamilyCaches) { - cache.clear(); - } -} |
