import fetch from 'isomorphic-unfetch'; import React, { createContext, useState, useEffect, useContext } from 'react'; type FetchProviderProps = { url?: string; options?: { [key: string]: any }; previewData?: any; children: React.ReactNode; }; type FetchContext = { loading: boolean; error?: string; data?: T; }; const FetchProviderContext = createContext | undefined>( undefined ); export const FetchProvider: React.FC = ({ url, options, previewData, children }) => { const [loading, setLoading] = useState(false); const [error, setError] = useState(); const [data, setData] = useState(); useEffect( () => { if (!loading) { setLoading(true); const fetchData = async () => { try { if (url) { const response = await fetch(url, options); const json = await response.json(); setData(json); setLoading(false); } else { throw new Error('must provide a Fetch url'); } } catch (err) { setError(err instanceof Error ? err.message : 'unknown error'); setLoading(false); } }; if (previewData) { setData(previewData); setLoading(false); } else { fetchData(); } } }, [url, options, previewData] ); return ( {children} ); }; export const useFetch = (): FetchContext => { const context: FetchContext = useContext( FetchProviderContext ) as FetchContext; if (context === undefined) { throw new Error('must be used within a FetchProvider'); } return context; };