🎣 Minimal hooks-first GraphQL client.
npm install graphql-hooks
or
yarn add graphql-hooks
> 1%, not deadConsider polyfilling:
FormDataPromisefetch. NOTE: A custom implementation can also be provided instead of polyfilling, see GraphQLClientFirst you'll need to create a client and wrap your app with the provider:
import { GraphQLClient, ClientContext } from 'graphql-hooks'
const client = new GraphQLClient({
url: '/graphql'
})
function App() {
return (
<ClientContext.Provider value={client}>
{/* children */}
</ClientContext.Provider>
)
}
Now in your child components you can make use of useQuery
import { useQuery } from 'graphql-hooks'
const HOMEPAGE_QUERY = `query HomePage($limit: Int) {
users(limit: $limit) {
id
name
}
}`
function MyComponent() {
const { loading, error, data } = useQuery(HOMEPAGE_QUERY, {
variables: {
limit: 10
}
})
if (loading) return 'Loading...'
if (error) return 'Something Bad Happened'
return (
<ul>
{data.users.map(({ id, name }) => (
<li key={id}>{name}</li>
))}
</ul>
)
}
graphql-hooks?The first thing you may ask when seeing graphql-hooks is "Why not use Apollo hooks?".
It's the comparison most will make. In fact, there's an article comparing the two over on LogRocket.
We believe graphql-hooks is a great choice as a hooks-first GraphQL client due to its concise API and package size.
In terms of performance, this is more of a grey area as we have no official benchmarks yet.
If you need a client that offers more customization such as advanced cache configuration, then apollo-hooks may work out to be a good choice for your project if bundle size is not an issue.
| Pros | Cons |
|---|---|
| Small in size | Less "advanced" caching configuration |
| Concise API | |
| Quick to get up and running |
GraphQLClientUsage:
import { GraphQLClient } from 'graphql-hooks'
const client = new GraphQLClient(config)
config: Object containing configuration properties
url: The URL of your GraphQL HTTP server. If not specified, you must enable fullWsTransport and provide a valid subscriptionClient; otherwise is required.fullWsTransport: Boolean - set to true if you want to use subscriptionClient to also send query and mutations via WebSocket; defaults to falsessrMode: Boolean - set to true when using on the server for server-side rendering; defaults to falseuseGETForQueries: Boolean - set to true to use HTTP GET method for all queries; defaults to false. See HTTP Get Support for more infosubscriptionClient: The WebSocket client configuration. Accepts either an instance of SubscriptionClient from subscriptions-transport-ws or Client from graphql-ws. A factory function is also accepted e.g. to avoid the creation of the client in SSR environments.cache (Required if ssrMode is true, otherwise optional): Object with the following methods:cache.get(key)cache.set(key, data)cache.delete(key)cache.clear()cache.keys()getInitialState()fetch(url, options): Fetch implementation - defaults to the global fetch API. Check Request interceptors for more details how to manage fetch.FormData: FormData implementation - defaults to the global FormData API. Polyfill this in a node.js environment. See file-uploads-nodejs for more info.fetchOptions: See MDN for info on what options can be passedheaders: Object, e.g. { 'My-Header': 'hello' }logErrors: Boolean - defaults to truemiddleware: Accepts an array of middleware functions, default: none, see more in middlewares readmeonError({ operation, result }): Custom error handleroperation: Object with query, variables and operationNameresult: Object containing data, headers and error object that contains fetchError, httpError and graphqlErrorsclient methodsclient.setHeader(key, value): Updates client.headers adding the new header to the existing headersclient.setHeaders(headers): Replaces client.headersclient.removeHeader(key): Updates client.headers removing the header if it existsclient.logErrorResult({ operation, result }): Default error logger; useful if you'd like to use it inside your custom onError handlerrequest(operation, options): Make a request to your GraphQL server; returning a Promiseoperation: Object with query, variables and operationNameoptions.fetchOptionsOverrides: Object containing additional fetch options to be added to the default ones passed to new GraphQLClient(config)options.responseReducer: Reducer function to pick values from the original Fetch Response object. Values are merged to the request response under the data key. Example usage: {responseReducer: (data, response) => ({...data, myKey: response.headers.get('content-length)})client.invalidateQuery(query): Will delete the older cache, re-fetch the new data using the same query, and store it in the cache as a new valuequery: The GraphQL query as a plain string to be re-fetched, or an Operation object (with query, variables and operationName)client.setQueryData(query, (oldState) => [...oldState, newState]]): Will override the older cache state with the new one provided by the function returnquery: The GraphQL query as a plain string, or an Operation object (with query, variables and operationName)(oldState) => [...oldState, newState]]: The callback function with returns will be the new state stored in the cache.oldState: The old value stored in the cacheClientContextClientContext is the result of React.createContext() - meaning it can be used directly with React's new context API:
Example:
import { ClientContext } from 'graphql-hooks'
function App() {
return (
<ClientContext.Provider value={client}>
{/* children can now consume the client context */}
</ClientContext.Provider>
)
}
To access the GraphQLClient instance, call React.useContext(ClientContext):
import React, { useContext } from 'react'
import { ClientContext } from 'graphql-hooks'
function MyComponent() {
const client = useContext(ClientContext)
}
useQueryUsage:
const state = useQuery(query, [options])
Example:
import { useQuery } from 'graphql-hooks'
function MyComponent() {
const { loading, error, data } = useQuery(query)
if (loading) return 'Loading...'
if (error) return 'Something bad happened'
return
{data.thing}
}
This is a custom hook that takes care of fetching your query and storing the result in the cache. It won't refetch the query unless query or options.variables changes.
query: Your GraphQL query as a plain string or DocumentNodeoptions: Object with the following optional propertiesvariables: Object e.g. { limit: 10 }operationName: If your query has multiple operations, pass the name of the operation you wish to execute.persisted: Boolean - defaults to false; Pass true if your graphql server supports persisted flag to serve persisted queries.useCache: Boolean - defaults to true; cache the query resultskip: Boolean - defaults to false; do not execute the query if set to trueskipCache: Boolean - defaults to false; If true it will by-pass the cache and fetch, but the result will then be cached for subsequent calls. Note the refetch function will do this automaticallyssr: Boolean - defaults to true. Set to false if you wish to skip this query during SSRfetchOptionsOverrides: Object - Specific overrides for this query. See MDN for info on what options can be passedupdateData(previousData, data): Function - Custom handler for merging previous & new query results; return value will replace data in useQuery return valuepreviousData: Previous GraphQL query or updateData resultdata: New GraphQL query resultclient: GraphQLClient - If a GraphQLClient is explicitly passed as an option, then it will be used instead of the client from the ClientContext.refetchAfterMutations: String | Object | (String | Object)[] - You can specify when a mutation should trigger query refetch.mutation: String - The mutation stringrefetchOnMutationError: boolean (optional, defaults to true) - It indicates whether the query must be re-fetched if the mutation returns an errorfilter: Function (optional) - It receives mutation's variables as parameter and blocks refetch if it returns falseuseQuery return valueconst { loading, error, data, refetch, cacheHit } = useQuery(QUERY)
loading: Boolean - true if the query is in flightdata: Object - the result of your GraphQL queryheaders: Object - response headersrefetch(options): Function - useful when refetching the same query after a mutation; NOTE this presets skipCache=true & will bypass the options.updateData function that was passed into useQuery. You can pass a new updateData into refetch if necessary.options: Object - options that will be merged into the options that were passed into useQuery (see above).cacheHit: Boolean - true if the query result came from the cache, useful for debuggingerror: Object - Set if at least one of the following errors has occurred and contains:fetchError: Object - Set if an error occurred during the fetch callhttpError: Object - Set if an error response was returned from the servergraphQLErrors: Array - Populated if any errors occurred whilst resolving the queryuseManualQueryUse this when you don't want a query to automatically be fetched or wish to call a query programmatically.
Usage:
const [queryFn, state] = useManualQuery(query, [options])
Example:
import { useManualQuery } from 'graphql-hooks'
function MyComponent(props) {
const [fetchUser, { loading, error, data }] = useManualQuery(GET_USER_QUERY, {
variables: { id: props.userId }
})
return (
<button onClick={fetchUser}>Get User!</button>
{error &&
Failed to fetch user
}
{loading &&
Loading...
}
{data &&
Hello ${data.user.name}
}
)
}
If you don't know certain options when declaring the useManualQuery you can also pass the same options to the query function itself when calling it:
```js import { useManualQuery }
$ claude mcp add graphql-hooks \
-- python -m otcore.mcp_server <graph>