# HandleRender helper, useQuery w/ internet check - Thurs 22 Oct, 020
Productive day yesterday and learnt a lot.
### `HandleRender` component
Built a component to manage the different render states of most of the C+ screens. For example: nearly all should have a no internet state, no results state, "has content" state:
```typescript=
interface HandleRenderProps {
/** Loading state from Apollo's useQuery/useMutation hooks */
loading: boolean
/** Error state from Apollo's useQuery/useMutation hooks */
error: ApolloError | undefined
/** If the content should be displayed, you can pass a custom evaluation here (e.g. if comments array length > 0) */
hasContent: boolean
/** A way for the user to retry the network request (usually `refetch`) */
onPress: () => void
/** The title to be shown when simply no content. Defaults to generic message. */
noContentTitle?: string
/** Optional no content description */
noContentDescription?: string
}
export const HandleRender: React.FC<HandleRenderProps> = ({
children,
loading,
error,
hasContent,
onPress,
noContentTitle = ERROR_MESSAGES.noContent.title,
noContentDescription = ERROR_MESSAGES.noContent.description,
}) => {
const netInfo = useNetInfo()
/** netInfo.isInternetReachable is checking if the internet is available which means there is a second where it returns null/undefined while its performing the check, which can cause a flash of the wrong content. Assume internet is connected unless netInfo.isInternetReachable explicitly returns false. */
const isInternetReachable = netInfo.isInternetReachable ?? true
switch (true) {
/** if loading */
case loading:
return <Loading />
/** if there is content */
case hasContent:
return <>{children}</>
/** if there is no internet */
case !isInternetReachable:
return (
<Error
errorType="no internet"
title={ERROR_MESSAGES.noInternet.title}
description={ERROR_MESSAGES.noInternet.description}
onPress={async () => {
try {
await onPress()
} catch (error) {
// eslint-disable-next-line no-console
console.warn('Error refetching: ', error)
}
}}
/>
)
/** if there is a problem fetching data */
case Boolean(error):
return (
<Error
errorType="error"
title={ERROR_MESSAGES.general}
onPress={async () => {
try {
await onPress()
} catch (error) {
// eslint-disable-next-line no-console
console.warn('Error refetching: ', error)
}
}}
/>
)
/** if there isn't any content, but there is internet and no errors */
default:
return <Error errorType="no results" title={noContentTitle} description={noContentDescription} />
}
}
```
### Custom `useQuery` / `useMutation` hooks
I found the existing Apollo Client hooks don't give good errors when there is no internet connection (at least on React Native). As such, I extended the hooks to use the NetInfo information too:
```typescript=
type MutationTuple<TData, TVariables> = [
(options?: MutationFunctionOptions<TData, TVariables>) => Promise<FetchResult<TData>>,
MutationResult<TData> & { netInfo: NetInfoState }
]
/** Extends Apollo's `useMutation` hook to include network status information */
export const useMutation = <TData = any, TVariables = OperationVariables>(
mutation: DocumentNode,
options?: MutationHookOptions<TData, TVariables>
): MutationTuple<TData, TVariables> => {
const netInfo = useNetInfo()
const base = useApolloMutation<TData, TVariables>(mutation, options)
/** netInfo.isInternetReachable is checking if the internet is available which means there is a second where it returns null/undefined while its performing the check, which can cause a flash of the wrong content. Assume internet is connected unless netInfo.isInternetReachable explicitly returns false. */
const isInternetReachable = netInfo.isInternetReachable ?? true
const loading = base[1].loading && isInternetReachable
return [
base[0],
{
...base[1],
loading,
netInfo: {
...netInfo,
isInternetReachable,
} as NetInfoState,
},
]
}
```
I had to type assert `NetInfoState` due to some incorrect types with the library.
### MockedProvider errors and loading
It's now much easier to test your component's `loading` and `error` states with Apollo Client 3's `MockedProvider`:
```typescript=
export const myQuery: MockedResponse<MyQuery> = {
request: {
query: MY_QUERY,
},
result: {
data: {
queryData: stuff,
},
},
// will be loading for 2 seconds
delay: 2000,
// will then resolve to an error
error: {
name: 'Error',
message: 'There was an error',
},
}
```
###### tags: `programmingjournal` `2020` `C+` `handlerender` `errorhandling` `useQuery` `useMutation` `mockedprovider`