aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/src/hooks/usePaginatedArticles.ts
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-14 12:17:23 +0900
committernsfisis <nsfisis@gmail.com>2026-02-14 12:17:23 +0900
commitfffd36268a216044523c3f5227c3d375608c36dc (patch)
treeb289735cb9d478af763775af9b15214b9595e747 /frontend/src/hooks/usePaginatedArticles.ts
parent2889b562e64993482bd13fd806af8ed0865bab8b (diff)
downloadfeedaka-fffd36268a216044523c3f5227c3d375608c36dc.tar.gz
feedaka-fffd36268a216044523c3f5227c3d375608c36dc.tar.zst
feedaka-fffd36268a216044523c3f5227c3d375608c36dc.zip
refactor(frontend): migrate state management to jotai and jotai-tanstack-query
Replace React Context + manual useEffect data fetching with jotai atoms for state management and jotai-tanstack-query for server state caching. - Add jotai, jotai-tanstack-query, @tanstack/query-core dependencies - Create atoms for auth (primitive + action), feeds (suspense query), and articles (infinite query with cursor-based pagination) - Wire up Provider, HydrateQueryClient, and StoreInitializer in main.tsx - Migrate all components from useAuth() context to jotai atoms - Replace manual fetch logic in FeedSidebar/FeedList with feedsAtom - Replace usePaginatedArticles hook with articlesInfiniteAtom - Add queryClient.invalidateQueries() after mutations for automatic cache refresh - Add ErrorBoundary and LoadingSpinner components for Suspense support - Remove callback prop chains (onFeedAdded, onFeedChanged, etc.) in favor of query invalidation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'frontend/src/hooks/usePaginatedArticles.ts')
-rw-r--r--frontend/src/hooks/usePaginatedArticles.ts80
1 files changed, 0 insertions, 80 deletions
diff --git a/frontend/src/hooks/usePaginatedArticles.ts b/frontend/src/hooks/usePaginatedArticles.ts
index 5ddf888..e69de29 100644
--- a/frontend/src/hooks/usePaginatedArticles.ts
+++ b/frontend/src/hooks/usePaginatedArticles.ts
@@ -1,80 +0,0 @@
-import { useCallback, useEffect, useState } from "react";
-import type { components } from "../api/generated";
-import { api } from "../services/api-client";
-
-export type ArticleType = components["schemas"]["Article"];
-
-interface UsePaginatedArticlesOptions {
- isReadView: boolean;
- feedId: string | null;
-}
-
-interface UsePaginatedArticlesResult {
- articles: ArticleType[];
- hasNextPage: boolean;
- loading: boolean;
- loadingMore: boolean;
- loadMore: () => void;
- error: Error | null;
-}
-
-export function usePaginatedArticles({
- isReadView,
- feedId,
-}: UsePaginatedArticlesOptions): UsePaginatedArticlesResult {
- const [articles, setArticles] = useState<ArticleType[]>([]);
- const [hasNextPage, setHasNextPage] = useState(false);
- const [endCursor, setEndCursor] = useState<string | null>(null);
- const [loading, setLoading] = useState(true);
- const [loadingMore, setLoadingMore] = useState(false);
- const [error, setError] = useState<Error | null>(null);
-
- const fetchArticles = useCallback(
- async (after: string | null, append: boolean) => {
- const query: { feedId?: string; after?: string } = {};
- if (feedId) query.feedId = feedId;
- if (after) query.after = after;
-
- const endpoint = isReadView
- ? "/api/articles/read"
- : "/api/articles/unread";
-
- const { data } = await api.GET(endpoint, {
- params: { query },
- });
-
- if (!data) {
- setError(new Error("Failed to fetch articles"));
- return;
- }
-
- if (data) {
- setArticles((prev) =>
- append ? [...prev, ...data.articles] : data.articles,
- );
- setHasNextPage(data.pageInfo.hasNextPage);
- setEndCursor(data.pageInfo.endCursor ?? null);
- setError(null);
- }
- },
- [isReadView, feedId],
- );
-
- // Reset and fetch on feedId or view change
- useEffect(() => {
- setArticles([]);
- setEndCursor(null);
- setHasNextPage(false);
- setLoading(true);
- setError(null);
- fetchArticles(null, false).finally(() => setLoading(false));
- }, [fetchArticles]);
-
- const loadMore = useCallback(() => {
- if (!hasNextPage || loadingMore) return;
- setLoadingMore(true);
- fetchArticles(endCursor, true).finally(() => setLoadingMore(false));
- }, [fetchArticles, endCursor, hasNextPage, loadingMore]);
-
- return { articles, hasNextPage, loading, loadingMore, loadMore, error };
-}