UNPKG

@ai-growth/nextjs

Version:

Seamlessly integrate Sanity CMS with Next.js applications for automated blog routing and rendering

255 lines (254 loc) 8.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useCmsContent = useCmsContent; exports.useCmsContentById = useCmsContentById; const react_1 = require("react"); const utils_1 = require("../utils"); const contentCache = new Map(); /** * React hook for fetching CMS content by slug with comprehensive state management */ function useCmsContent(slug, options = {}) { const { contentType = 'post', initialData = null, enabled = true, staleTime = 5 * 60 * 1000, // 5 minutes cacheTime = 10 * 60 * 1000, // 10 minutes refetchOnWindowFocus = false, refetchOnReconnect = true, onSuccess, onError, ...fetchOptions } = options; const [content, setContent] = (0, react_1.useState)(initialData); const [isLoading, setIsLoading] = (0, react_1.useState)(!initialData && enabled && !!slug); const [isError, setIsError] = (0, react_1.useState)(false); const [error, setError] = (0, react_1.useState)(null); const [isFetching, setIsFetching] = (0, react_1.useState)(false); // Generate cache key const cacheKey = (0, react_1.useMemo)(() => { if (!slug) return null; return `${contentType}:${slug}:${JSON.stringify(fetchOptions)}`; }, [slug, contentType, fetchOptions]); // Check if cached data is stale const isStale = (0, react_1.useMemo)(() => { if (!cacheKey) return false; const cached = contentCache.get(cacheKey); if (!cached) return true; return Date.now() - cached.timestamp > cached.staleTime; }, [cacheKey, content]); // Fetch content function const fetchContent = (0, react_1.useCallback)(async () => { if (!slug || !enabled || !cacheKey) return; // Check cache first const cached = contentCache.get(cacheKey); if (cached && !isStale && !isFetching) { setContent(cached.data); setIsLoading(false); setIsError(false); setError(null); return; } try { setIsFetching(true); setIsError(false); setError(null); // Use the appropriate content fetching function const data = await (0, utils_1.fetchContentBySlug)(contentType, slug, fetchOptions); if (data) { // Cache the result contentCache.set(cacheKey, { data, timestamp: Date.now(), staleTime, }); setContent(data); setIsLoading(false); onSuccess?.(data); } else { throw new Error(`Content not found for slug: ${slug}`); } } catch (err) { const errorObj = err instanceof Error ? err : new Error(String(err)); setError(errorObj); setIsError(true); setContent(null); setIsLoading(false); onError?.(errorObj); } finally { setIsFetching(false); } }, [ slug, enabled, cacheKey, contentType, fetchOptions, staleTime, isStale, isFetching, onSuccess, onError, ]); // Refetch function for manual refresh const refetch = (0, react_1.useCallback)(async () => { if (cacheKey) { contentCache.delete(cacheKey); // Clear cache } await fetchContent(); }, [cacheKey, fetchContent]); // Reset function to clear state const reset = (0, react_1.useCallback)(() => { setContent(initialData); setIsLoading(!initialData && enabled && !!slug); setIsError(false); setError(null); setIsFetching(false); }, [initialData, enabled, slug]); // Initial fetch effect (0, react_1.useEffect)(() => { if (slug && enabled) { fetchContent(); } }, [fetchContent]); // Window focus refetch (0, react_1.useEffect)(() => { if (!refetchOnWindowFocus) return; const handleFocus = () => { if (slug && enabled && isStale) { fetchContent(); } }; window.addEventListener('focus', handleFocus); return () => window.removeEventListener('focus', handleFocus); }, [refetchOnWindowFocus, slug, enabled, isStale, fetchContent]); // Online/reconnect refetch (0, react_1.useEffect)(() => { if (!refetchOnReconnect) return; const handleOnline = () => { if (slug && enabled && isStale) { fetchContent(); } }; window.addEventListener('online', handleOnline); return () => window.removeEventListener('online', handleOnline); }, [refetchOnReconnect, slug, enabled, isStale, fetchContent]); // Cache cleanup (0, react_1.useEffect)(() => { const cleanup = () => { const now = Date.now(); for (const [key, entry] of contentCache.entries()) { if (now - entry.timestamp > cacheTime) { contentCache.delete(key); } } }; const interval = setInterval(cleanup, cacheTime); return () => clearInterval(interval); }, [cacheTime]); return { content, isLoading, isError, error, isFetching, isStale, refetch, reset, }; } /** * React hook for fetching CMS content by ID */ function useCmsContentById(id, options = {}) { const { initialData = null, enabled = true, staleTime = 5 * 60 * 1000, onSuccess, onError, ...fetchOptions } = options; const [content, setContent] = (0, react_1.useState)(initialData); const [isLoading, setIsLoading] = (0, react_1.useState)(!initialData && enabled && !!id); const [isError, setIsError] = (0, react_1.useState)(false); const [error, setError] = (0, react_1.useState)(null); const [isFetching, setIsFetching] = (0, react_1.useState)(false); const cacheKey = (0, react_1.useMemo)(() => { if (!id) return null; return `id:${id}:${JSON.stringify(fetchOptions)}`; }, [id, fetchOptions]); const isStale = (0, react_1.useMemo)(() => { if (!cacheKey) return false; const cached = contentCache.get(cacheKey); if (!cached) return true; return Date.now() - cached.timestamp > cached.staleTime; }, [cacheKey, content, staleTime]); const fetchContent = (0, react_1.useCallback)(async () => { if (!id || !enabled || !cacheKey) return; const cached = contentCache.get(cacheKey); if (cached && !isStale && !isFetching) { setContent(cached.data); setIsLoading(false); setIsError(false); setError(null); return; } try { setIsFetching(true); setIsError(false); setError(null); const data = await (0, utils_1.fetchContentById)(id, fetchOptions); if (data) { contentCache.set(cacheKey, { data, timestamp: Date.now(), staleTime, }); setContent(data); setIsLoading(false); onSuccess?.(data); } else { throw new Error(`Content not found for ID: ${id}`); } } catch (err) { const errorObj = err instanceof Error ? err : new Error(String(err)); setError(errorObj); setIsError(true); setContent(null); setIsLoading(false); onError?.(errorObj); } finally { setIsFetching(false); } }, [id, enabled, cacheKey, fetchOptions, staleTime, isStale, isFetching, onSuccess, onError]); const refetch = (0, react_1.useCallback)(async () => { if (cacheKey) { contentCache.delete(cacheKey); } await fetchContent(); }, [cacheKey, fetchContent]); const reset = (0, react_1.useCallback)(() => { setContent(initialData); setIsLoading(!initialData && enabled && !!id); setIsError(false); setError(null); setIsFetching(false); }, [initialData, enabled, id]); (0, react_1.useEffect)(() => { if (id && enabled) { fetchContent(); } }, [fetchContent]); return { content, isLoading, isError, error, isFetching, isStale, refetch, reset, }; }