import { isUndefined } from "lodash" ; import React , { useCallback , useEffect , useState } from "react" ; import { fetchQuery as relayFetchQuery } from "react-relay" ; import { compose , hoistStatics , InferableComponentEnhancer , wrapDisplayName , } from "recompose" ; import { CacheConfig , Environment , GraphQLTaggedNode , Variables , } from "relay-runtime" ; import { CoralContext , useCoralContext , withContext } from "../bootstrap" ; export interface Fetch < N , V , R > { name : N ; fetch : ( environment : Environment , variables : V , context : CoralContext ) => R ; } export type FetchVariables < T extends { variables : any ; } > = T [ "variables" ] ; export type FetchProp < T extends Fetch < any , any , any > > = T extends Fetch < any , infer V , infer R > ? Parameters < T [ "fetch" ] > [ 1 ] extends undefined ? ( ) => R : keyof Parameters < T [ "fetch" ] > [ 1 ] extends never ? ( ) => R : ( variables : V ) => R : never ; export function createFetch < N extends string , V , R > ( name , fetch ) { return { name , fetch , } as any ; } export async function fetchQuery < T extends { response : any ; } > ( environment , taggedNode , variables , cacheConfig ? ) { return relayFetchQuery ( environment , taggedNode , variables , cacheConfig ) ; } /**
 * useFetch is a React Hook that
 * returns a callback to call the fetch.
 */ export function useFetch < V , R > ( fetch ) { const context = useCoralContext ( ) ; return useCallback < FetchProp < typeof fetch > > ( ( ( variables ) => { context . eventEmitter . emit ( `fetch.${ fetch . name }` , variables ) ; return fetch . fetch ( context . relayEnvironment , variables , context ) ; } ) as any , [ context ] ) ; } export function useImmediateFetch < V extends { } , R > ( fetch , variables , refetch ? ) { const fetcher = useFetch ( fetch ) ; const [ state , setState ] = useState < { data : R | null ; loading : boolean ; } > ( { data : null , loading : false , } ) ; useEffect ( ( ) => { let aborted = false ; async function doTheFetch ( ) { setState ( ( s ) => ( { ... s , loading : true } ) ) ; try { const data = await fetcher ( variables ) ; if ( aborted ) { return ; } setState ( { data , loading : false } ) ; } catch ( err ) { console . error ( "could not perform fetch" , err ) ; setState ( { data : null , loading : false } ) ; } } void doTheFetch ( ) ; return ( ) => { aborted = true ; } ; } , Object . values ( variables ) . concat ( isUndefined ( refetch ) ? [ ] : [ refetch ] ) ) ; return [ state . data , state . loading ] ; } deprecated export function withFetch < N extends string , V , R > ( fetch ) { return compose ( withContext ( ( context ) => ( { context } ) ) , hoistStatics ( ( BaseComponent ) => { class WithFetch extends React . Component < { context : CoralContext ; } > { public static displayName = wrapDisplayName ( BaseComponent , "withFetch" ) ; private fetch = ( variables ) => { this . props . context . eventEmitter . emit ( `fetch.${ fetch . name }` , variables ) ; return fetch . fetch ( this . props . context . relayEnvironment , variables , this . props . context ) ; } ; public render ( ) { const { context : _ , ... rest } = this . props ; const inject = { [ fetch . name ] : this . fetch , } ; return < BaseComponent { ... rest } { ... inject } />; } } return WithFetch as React . ComponentClass < any > ; } ) ) as any ; }