From fffd36268a216044523c3f5227c3d375608c36dc Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 14 Feb 2026 12:17:23 +0900 Subject: 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 --- frontend/src/contexts/AuthContext.tsx | 74 ----------------------------------- 1 file changed, 74 deletions(-) (limited to 'frontend/src/contexts/AuthContext.tsx') diff --git a/frontend/src/contexts/AuthContext.tsx b/frontend/src/contexts/AuthContext.tsx index 9b157cb..e69de29 100644 --- a/frontend/src/contexts/AuthContext.tsx +++ b/frontend/src/contexts/AuthContext.tsx @@ -1,74 +0,0 @@ -import { - createContext, - type ReactNode, - useCallback, - useContext, - useEffect, - useState, -} from "react"; -import { api } from "../services/api-client"; - -type LoginResult = { success: true } | { success: false; error: string }; - -interface AuthContextType { - isLoggedIn: boolean; - isLoading: boolean; - login: (username: string, password: string) => Promise; - logout: () => Promise; -} - -const AuthContext = createContext(undefined); - -export function AuthProvider({ children }: { children: ReactNode }) { - const [isLoggedIn, setIsLoggedIn] = useState(false); - const [isLoading, setIsLoading] = useState(true); - - const checkAuth = useCallback(async () => { - const { data } = await api.GET("/api/auth/me"); - setIsLoggedIn(!!data); - setIsLoading(false); - }, []); - - useEffect(() => { - checkAuth(); - }, [checkAuth]); - - const login = async ( - username: string, - password: string, - ): Promise => { - const { data, error } = await api.POST("/api/auth/login", { - body: { username, password }, - }); - - if (error) { - return { success: false, error: error.message }; - } - - if (data?.user) { - setIsLoggedIn(true); - return { success: true }; - } - - return { success: false, error: "Invalid username or password" }; - }; - - const logout = async () => { - await api.POST("/api/auth/logout"); - setIsLoggedIn(false); - }; - - return ( - - {children} - - ); -} - -export function useAuth() { - const context = useContext(AuthContext); - if (context === undefined) { - throw new Error("useAuth must be used within an AuthProvider"); - } - return context; -} -- cgit v1.3-1-g0d28