Skip to content

Instantly share code, notes, and snippets.

@jaredly
Created December 20, 2017 00:58
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaredly/a9ca0626db6beaab3d18e3a76cfb77ec to your computer and use it in GitHub Desktop.
Save jaredly/a9ca0626db6beaab3d18e3a76cfb77ec to your computer and use it in GitHub Desktop.
// @flow
import {Component, type Node} from 'react'
import authenticatedApolloClient from '../shared/authenticatedApolloClient';
/**
* Example usage:
*
* const ScreenWithLoader = (props) => <ApolloWrapper
* queryOptions={{
* query: SomeQuery,
* variables: {
* subjectId: props.subjectId,
* topicId: props.topicId,
* }
* }}
* renderLoading={SimpleLoading}
* renderFailed={(error, refetch) => <ErrorScreen message={strings.topic_error} refetch={refetch} />}
* render={(data, refetch) => <StreamingTopic {...props} data={data} refetch={refetch} />}
* />
*/
type Props<T> = {
queryOptions: {
query: *,
variables: *,
},
render: (data: T, refetch: () => void) => Node,
renderLoading: () => Node,
renderFailed: (error: Error, refetch: () => void) => Node,
}
type QueryState<T> = {
status: 'loading',
} | {
status: 'failed',
error: Error,
} | {
status: 'loaded',
data: T
}
type State<T> = {queryState: QueryState<T>}
export default class ApolloWrapper extends Component<Props<*>, State<*>> {
state = {
queryState: {status: 'loading'},
}
_unmounted: boolean
componentDidMount() {
this.refetch(true)
}
componentWillUnmount() {
this._unmounted = true
}
refetch = (cacheFirst: boolean = false) => {
this.setState({queryState: {status: 'loading'}})
authenticatedApolloClient.query({
...this.props.queryOptions,
strategy: cacheFirst ? 'cache-first' : 'network-only',
})
.then(response => {
if (this._unmounted) {
return
}
this.setState({queryState: {status: 'loaded', data: response.data}})
}, error => {
if (this._unmounted) {
return
}
if (error.networkError !== 'timeout') {
// If we get something other than a timeout, be loud about it
console.error(error); // eslint-disable-line no-console
}
this.setState({queryState: {status: 'failed', error: error}})
})
}
render() {
const {queryState} = this.state
if (queryState.status === 'loading') {
return this.props.renderLoading()
} else if (queryState.status === 'failed') {
return this.props.renderFailed(queryState.error, this.refetch)
} else {
return this.props.render(queryState.data, this.refetch)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment