aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/client/atoms/study.ts
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-01 10:16:35 +0900
committernsfisis <nsfisis@gmail.com>2026-02-01 10:16:38 +0900
commita07dada0c9ba80976692ee14e256da0a2d6b0112 (patch)
tree7de73126b4e69ed3e2128e19da2eca56fe4f9e68 /src/client/atoms/study.ts
parent081498168fe25b377f4675637c57a08e4e399f95 (diff)
downloadkioku-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/study.ts')
-rw-r--r--src/client/atoms/study.ts42
1 files changed, 23 insertions, 19 deletions
diff --git a/src/client/atoms/study.ts b/src/client/atoms/study.ts
index 2e3e1ea..1911737 100644
--- a/src/client/atoms/study.ts
+++ b/src/client/atoms/study.ts
@@ -1,6 +1,7 @@
+import { atomFamily } from "jotai/utils";
+import { atomWithSuspenseQuery } from "jotai-tanstack-query";
import { apiClient } from "../api/client";
import { shuffle } from "../utils/shuffle";
-import { createReloadableAtomFamily } from "./utils";
export interface StudyCard {
id: string;
@@ -36,24 +37,27 @@ export interface StudyData {
// Study Session - Suspense-compatible
// =====================
-export const studyDataAtomFamily = createReloadableAtomFamily(
- async (deckId: string): Promise<StudyData> => {
- // Fetch deck and due cards in parallel
- const [deckRes, cardsRes] = await Promise.all([
- apiClient.rpc.api.decks[":id"].$get({ param: { id: deckId } }),
- apiClient.rpc.api.decks[":deckId"].study.$get({ param: { deckId } }),
- ]);
+export const studyDataAtomFamily = atomFamily((deckId: string) =>
+ atomWithSuspenseQuery(() => ({
+ queryKey: ["decks", deckId, "study"],
+ queryFn: async (): Promise<StudyData> => {
+ // Fetch deck and due cards in parallel
+ const [deckRes, cardsRes] = await Promise.all([
+ apiClient.rpc.api.decks[":id"].$get({ param: { id: deckId } }),
+ apiClient.rpc.api.decks[":deckId"].study.$get({ param: { deckId } }),
+ ]);
- const deckData = await apiClient.handleResponse<{ deck: StudyDeck }>(
- deckRes,
- );
- const cardsData = await apiClient.handleResponse<{ cards: StudyCard[] }>(
- cardsRes,
- );
+ const deckData = await apiClient.handleResponse<{ deck: StudyDeck }>(
+ deckRes,
+ );
+ const cardsData = await apiClient.handleResponse<{
+ cards: StudyCard[];
+ }>(cardsRes);
- return {
- deck: deckData.deck,
- cards: shuffle(cardsData.cards),
- };
- },
+ return {
+ deck: deckData.deck,
+ cards: shuffle(cardsData.cards),
+ };
+ },
+ })),
);