Created
November 22, 2024 16:51
-
-
Save WomB0ComB0/6d2b70f7077fb872cbf5dfe212d60164 to your computer and use it in GitHub Desktop.
Client-side fetch component to reduce excessive re-writing of the same sequence of code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use client'; | |
import React, { Suspense } from 'react'; | |
import { ClientError, Loader } from '@/components' | |
import { fetcher } from "@/lib" | |
import { useSuspenseQuery } from '@tanstack/react-query'; | |
import { catchError, parseCodePath } from '@/utils'; | |
/** | |
* A React component that handles data fetching with built-in loading, error handling, and caching. | |
* Uses React Suspense and TanStack Query for efficient data management and rendering. | |
* | |
* @component | |
* @template T - The type of data being fetched | |
* | |
* @param {Object} props - Component props | |
* @param {string} props.url - The base URL to fetch data from | |
* @param {Record<string, string>} [props.params] - Optional query parameters to append to the URL | |
* @param {(data: T) => React.ReactNode} props.children - Render prop function that receives the fetched data | |
* | |
* @example | |
* ```tsx | |
* // Basic usage | |
* <DataLoader url="/api/users"> | |
* {(data) => <UserList users={data} />} | |
* </DataLoader> | |
* | |
* // With query parameters | |
* <DataLoader | |
* url="/api/posts" | |
* params={{ category: "tech", limit: "10" }} | |
* > | |
* {(data) => <PostGrid posts={data} />} | |
* </DataLoader> | |
* ``` | |
* | |
* @remarks | |
* - Implements automatic retrying and revalidation every 5 minutes | |
* - Caches data for 5 minutes before considering it stale | |
* - Shows loading spinner during data fetching | |
* - Handles and displays errors with ClientError component | |
* - Uses catchError utility for clean error handling | |
* - Supports URL query parameters | |
* - Integrates with React Suspense for loading states | |
*/ | |
export const DataLoader: React.FC<{ | |
url: string, | |
params?: Record<string, string>, | |
children: (data: any) => React.ReactNode | |
}> = ({ url, params, children }) => { | |
const { data, error } = useSuspenseQuery({ | |
queryKey: [url, params], | |
queryFn: async () => { | |
const searchParams = params ? `?${new URLSearchParams(params)}` : ''; | |
const fullUrl = `${url}${searchParams}`; | |
const [fetchError, response] = await catchError( | |
fetcher<any>(fullUrl).then(res => { | |
if (!res.ok) { | |
throw new Error(`${res.statusText} at DataLoader ${parseCodePath(fullUrl, fetch)}`); | |
} | |
return res.json(); | |
}) | |
); | |
if (fetchError) throw fetchError; | |
return response; | |
}, | |
staleTime: 1000 * 60 * 5, | |
refetchInterval: 1000 * 60 * 5 | |
}); | |
return ( | |
<Suspense fallback={<Loader />}> | |
{error && <ClientError error={error} />} | |
{children(data)} | |
</Suspense> | |
); | |
}; | |
DataLoader.displayName = 'DataLoader'; | |
export default DataLoader; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment