diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-14 12:17:23 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-14 12:17:23 +0900 |
| commit | fffd36268a216044523c3f5227c3d375608c36dc (patch) | |
| tree | b289735cb9d478af763775af9b15214b9595e747 /frontend/src/contexts | |
| parent | 2889b562e64993482bd13fd806af8ed0865bab8b (diff) | |
| download | feedaka-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/contexts')
| -rw-r--r-- | frontend/src/contexts/AuthContext.tsx | 74 |
1 files changed, 0 insertions, 74 deletions
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<LoginResult>; - logout: () => Promise<void>; -} - -const AuthContext = createContext<AuthContextType | undefined>(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<LoginResult> => { - 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 ( - <AuthContext.Provider value={{ isLoggedIn, isLoading, login, logout }}> - {children} - </AuthContext.Provider> - ); -} - -export function useAuth() { - const context = useContext(AuthContext); - if (context === undefined) { - throw new Error("useAuth must be used within an AuthProvider"); - } - return context; -} |
