|
import * as React from 'react'; |
|
import { QueryResult } from 'react-apollo'; |
|
import { ApolloError } from 'apollo-client'; |
|
|
|
export enum QueryRendererState { |
|
LOADING, |
|
EXPECTED_ERROR, |
|
UNEXPECTED_ERROR, |
|
READY, |
|
} |
|
|
|
type QueryRenderHandler<P = {}> = React.FC<P>; |
|
|
|
interface QueryRendererHandlers<D> { |
|
[QueryRendererState.LOADING]: QueryRenderHandler; |
|
[QueryRendererState.EXPECTED_ERROR]: QueryRenderHandler<{ error: ApolloError }>; |
|
[QueryRendererState.UNEXPECTED_ERROR]: QueryRenderHandler; |
|
[QueryRendererState.READY]: QueryRenderHandler<D>; |
|
} |
|
|
|
type MakeOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>; |
|
|
|
type QueryRendererHandlersProp<D> = MakeOptional< |
|
QueryRendererHandlers<D>, |
|
QueryRendererState.LOADING | QueryRendererState.EXPECTED_ERROR | QueryRendererState.UNEXPECTED_ERROR |
|
>; |
|
|
|
function isChildrenReactComponent<D>(children: QueryRendererHandlersProp<D> | React.FC<D>): children is React.FC<D> { |
|
return typeof children === 'function'; |
|
} |
|
|
|
const defaultHandlers: Omit<QueryRendererHandlers<undefined>, QueryRendererState.READY> = { |
|
[QueryRendererState.LOADING]: () => <p>Loading...</p>, |
|
[QueryRendererState.EXPECTED_ERROR]: ({ error }) => <p>Expected error occured: {error.message}.</p>, |
|
[QueryRendererState.UNEXPECTED_ERROR]: () => <p>Unexpected error</p>, |
|
}; |
|
|
|
function QueryRenderer<QueryData, QueryVariables>({ |
|
query: { loading, error, data }, |
|
children, |
|
}: { |
|
query: QueryResult<QueryData, QueryVariables>; |
|
children: React.FC<QueryData> | QueryRendererHandlersProp<QueryData>; |
|
}): React.ReactElement | null { |
|
const handlers: QueryRendererHandlers<QueryData> = { |
|
...defaultHandlers, |
|
...(isChildrenReactComponent(children) ? { [QueryRendererState.READY]: children } : children), |
|
}; |
|
|
|
if (loading) { |
|
return handlers[QueryRendererState.LOADING]({}); |
|
} else if (error) { |
|
return handlers[QueryRendererState.EXPECTED_ERROR]({ error }); |
|
} else if (!data) { |
|
return handlers[QueryRendererState.UNEXPECTED_ERROR]({}); |
|
} else { |
|
return handlers[QueryRendererState.READY](data); |
|
} |
|
} |
|
|
|
export default QueryRenderer; |