Created
May 14, 2019 20:24
-
-
Save jaredpalmer/c2013f05935087fad36bc191c8f26fc6 to your computer and use it in GitHub Desktop.
Suspense-ready useQuery
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ApolloError } from 'apollo-boost'; | |
import { print } from 'graphql/language/printer'; | |
import React from 'react'; | |
const queries = new Map(); | |
const getCacheKey = ({ query, ...opts }) => | |
`${print(query)}@@${JSON.stringify(opts)}`; | |
const invalidateCachedQuery = options => | |
queries.delete(getCacheKey(options)); | |
const getCachedQuery = (client, options) => { | |
const cacheKey = getCacheKey(options); | |
let observableQuery = queries.get(cacheKey); | |
if (observableQuery == null) { | |
observableQuery = client.watchQuery(options); | |
queries.set(cacheKey, observableQuery); | |
} | |
return observableQuery; | |
}; | |
const actHack = fn => { | |
if (fn) { | |
fn(); | |
} | |
}; | |
export const ApolloContext = React.createContext(null); | |
export const ApolloProvider = props => ( | |
<ApolloContext.Provider value={props.client}> | |
{props.children} | |
</ApolloContext.Provider> | |
); | |
export function useQuery(query, vars) { | |
const client = React.useContext(ApolloContext); | |
const options = React.useMemo(() => ({ query, ...vars }), [ | |
query, | |
vars, | |
]); | |
const observableQuery = React.useMemo( | |
() => getCachedQuery(client, options), | |
[client, options] | |
); | |
const currentResult = React.useMemo(() => { | |
const result = observableQuery.currentResult(); | |
let data = result.data; | |
if (result.error || result.errors) { | |
data = { | |
...result.data, | |
...(observableQuery.getLastResult() || {}).data, | |
}; | |
} | |
return { | |
data, | |
error: | |
result.errors && result.errors.length > 0 | |
? new ApolloError({ graphQLErrors: result.errors }) | |
: result.error, | |
networkStatus: undefined, | |
partial: result.partial, | |
}; | |
}, [observableQuery]); | |
// eslint-disable-next-line no-unused-vars | |
const [responseId, setResponseId] = React.useState(0); | |
React.useEffect(() => { | |
const invalidateHack = () => { | |
actHack(() => { | |
setResponseId(x => x + 1); | |
}); | |
}; | |
const subscription = observableQuery.subscribe( | |
invalidateHack, | |
invalidateHack | |
); | |
invalidateCachedQuery(options); | |
return () => { | |
subscription.unsubscribe(); | |
}; | |
}, [observableQuery, options]); | |
if (currentResult.error != null && options.onError) { | |
options.onError(currentResult.error); | |
} | |
if (currentResult.partial) { | |
throw observableQuery.result(); | |
} | |
return currentResult; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment