api call optimized
This commit is contained in:
1 parent
97436c6823
commit
612259f020
12 files changed
+727
-177
No files matched your search
@@ -0,0 +1,141 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
useCallback,
|
||||
useRef,
|
||||
} from "react";
|
||||
import { useUser, useAuth } from "@clerk/clerk-expo";
|
||||
import {
|
||||
getRecommendations,
|
||||
generateRecommendation,
|
||||
type Recommendation,
|
||||
type GenerateRecommendationRequest,
|
||||
} from "../api/recommendations";
|
||||
import log from "../utils/logger";
|
||||
|
||||
interface RecommendationsContextValue {
|
||||
recommendations: Recommendation[];
|
||||
loading: boolean;
|
||||
error: Error | null;
|
||||
refetchRecommendations: () => Promise<void>;
|
||||
generateNewRecommendation: (
|
||||
data: GenerateRecommendationRequest,
|
||||
) => Promise<Recommendation>;
|
||||
clearCache: () => void;
|
||||
}
|
||||
|
||||
const RecommendationsContext = createContext<
|
||||
RecommendationsContextValue | undefined
|
||||
>(undefined);
|
||||
|
||||
export function RecommendationsProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { user } = useUser();
|
||||
const { getToken } = useAuth();
|
||||
const [recommendations, setRecommendations] = useState<Recommendation[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
const [lastFetchTime, setLastFetchTime] = useState<number>(0);
|
||||
const fetchInProgress = useRef(false);
|
||||
|
||||
// Cache recommendations for 30 seconds
|
||||
const CACHE_DURATION = 30000; // 30 seconds
|
||||
|
||||
const refetchRecommendations = useCallback(async () => {
|
||||
if (!user?.id) return;
|
||||
|
||||
// Prevent concurrent fetches
|
||||
if (fetchInProgress.current) {
|
||||
log.debug("Recommendations fetch already in progress, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we have recent cached data
|
||||
const now = Date.now();
|
||||
if (recommendations.length > 0 && now - lastFetchTime < CACHE_DURATION) {
|
||||
log.debug("Using cached recommendations", {
|
||||
count: recommendations.length,
|
||||
age: now - lastFetchTime,
|
||||
cacheRemaining: CACHE_DURATION - (now - lastFetchTime),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
fetchInProgress.current = true;
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
log.debug("Fetching fresh recommendations", { userId: user.id });
|
||||
|
||||
const token = await getToken();
|
||||
const data = await getRecommendations(user.id, token);
|
||||
|
||||
setRecommendations(data);
|
||||
setLastFetchTime(now);
|
||||
log.debug("Recommendations fetched and cached", { count: data.length });
|
||||
} catch (err) {
|
||||
const error = err instanceof Error ? err : new Error(String(err));
|
||||
log.error("Failed to fetch recommendations", error);
|
||||
setError(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
fetchInProgress.current = false;
|
||||
}
|
||||
}, [user?.id, getToken, recommendations.length, lastFetchTime]);
|
||||
|
||||
const generateNewRecommendation = useCallback(
|
||||
async (data: GenerateRecommendationRequest): Promise<Recommendation> => {
|
||||
if (!user?.id) throw new Error("User not authenticated");
|
||||
|
||||
const token = await getToken();
|
||||
const newRecommendation = await generateRecommendation(data, token);
|
||||
|
||||
// Optimistically update cache
|
||||
setRecommendations((prev) => [...prev, newRecommendation]);
|
||||
setLastFetchTime(Date.now());
|
||||
log.debug("Recommendation generated and added to cache", {
|
||||
recommendationId: newRecommendation.id,
|
||||
});
|
||||
|
||||
return newRecommendation;
|
||||
},
|
||||
[user?.id, getToken],
|
||||
);
|
||||
|
||||
const clearCache = useCallback(() => {
|
||||
setRecommendations([]);
|
||||
setLastFetchTime(0);
|
||||
setError(null);
|
||||
fetchInProgress.current = false;
|
||||
log.debug("Recommendations cache cleared");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<RecommendationsContext.Provider
|
||||
value={{
|
||||
recommendations,
|
||||
loading,
|
||||
error,
|
||||
refetchRecommendations,
|
||||
generateNewRecommendation,
|
||||
clearCache,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</RecommendationsContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useRecommendations() {
|
||||
const context = useContext(RecommendationsContext);
|
||||
if (context === undefined) {
|
||||
throw new Error(
|
||||
"useRecommendations must be used within a RecommendationsProvider",
|
||||
);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
Reference in new issue
Block a user