{"id":13450305,"url":"https://github.com/nearform/graphql-hooks","last_synced_at":"2025-05-13T15:11:40.951Z","repository":{"id":37444650,"uuid":"169704799","full_name":"nearform/graphql-hooks","owner":"nearform","description":"🎣 Minimal hooks-first GraphQL client","archived":false,"fork":false,"pushed_at":"2025-04-07T22:56:04.000Z","size":9577,"stargazers_count":1891,"open_issues_count":7,"forks_count":93,"subscribers_count":138,"default_branch":"master","last_synced_at":"2025-05-08T22:13:40.432Z","etag":null,"topics":["graphql","graphql-client","hacktoberfest","hooks","react","react-hooks"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nearform.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-02-08T08:29:00.000Z","updated_at":"2025-05-06T19:38:34.000Z","dependencies_parsed_at":"2024-07-22T09:31:45.849Z","dependency_job_id":"09593dda-8298-412a-afad-9f2271ad3095","html_url":"https://github.com/nearform/graphql-hooks","commit_stats":{"total_commits":805,"total_committers":100,"mean_commits":8.05,"dds":0.6385093167701863,"last_synced_commit":"95219cdcd98520aeebc7f413f294730052b042b8"},"previous_names":[],"tags_count":472,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nearform%2Fgraphql-hooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nearform%2Fgraphql-hooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nearform%2Fgraphql-hooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nearform%2Fgraphql-hooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nearform","download_url":"https://codeload.github.com/nearform/graphql-hooks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253154977,"owners_count":21862623,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["graphql","graphql-client","hacktoberfest","hooks","react","react-hooks"],"created_at":"2024-07-31T07:00:33.462Z","updated_at":"2025-05-13T15:11:35.935Z","avatar_url":"https://github.com/nearform.png","language":"TypeScript","funding_links":[],"categories":["Packages","TypeScript","Libraries","Implementations","JavaScript","🌐 Web Development - Frontend"],"sub_categories":["JavaScript Libraries","JavaScript/TypeScript"],"readme":"# graphql-hooks\n\n[![ci](https://github.com/nearform/graphql-hooks/workflows/ci/badge.svg)](https://github.com/nearform/graphql-hooks/actions?query=workflow%3Aci)\n[![Coverage Status](https://coveralls.io/repos/github/nearform/graphql-hooks/badge.svg?branch=master)](https://coveralls.io/github/nearform/graphql-hooks?branch=master)\n[![bundlephobia](https://img.shields.io/bundlephobia/minzip/graphql-hooks.svg?style=flat\u0026label=size)](https://bundlephobia.com/result?p=graphql-hooks)\n[![npm](https://img.shields.io/npm/v/graphql-hooks.svg?color=brightgreen)](https://www.npmjs.com/package/graphql-hooks)\n[![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lernajs.io/)\n\n🎣 Minimal hooks-first GraphQL client.\n\n## Features\n\n- 🥇 First-class hooks API\n- ⚖️ _Tiny_ bundle: only 22.9kB (7.4kB gzipped)\n- 📄 Full SSR support: see [graphql-hooks-ssr](packages/graphql-hooks-ssr)\n- 🔌 Plugin Caching: see [graphql-hooks-memcache](packages/graphql-hooks-memcache)\n- 🔥 No more render props hell\n- ⏳ Handle loading and error states with ease\n\n## Install\n\n`npm install graphql-hooks`\n\nor\n\n`yarn add graphql-hooks`\n\n## Support\n\n- Node LTS\n- Browsers [`\u003e 1%, not dead`](https://browserl.ist/?q=%3E+1%25%2C+not+dead)\n\nConsider polyfilling:\n\n- [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData)\n- [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\n- [`fetch`](https://developer.mozilla.org/docs/Web/API/Fetch_API). NOTE: A custom implementation can also be provided instead of polyfilling, [see `GraphQLClient`](#GraphQLClient)\n\n## Quick Start\n\nFirst you'll need to create a client and wrap your app with the provider:\n\n```js\nimport { GraphQLClient, ClientContext } from 'graphql-hooks'\n\nconst client = new GraphQLClient({\n  url: '/graphql'\n})\n\nfunction App() {\n  return (\n    \u003cClientContext.Provider value={client}\u003e\n      {/* children */}\n    \u003c/ClientContext.Provider\u003e\n  )\n}\n```\n\nNow in your child components you can make use of `useQuery`\n\n```js\nimport { useQuery } from 'graphql-hooks'\n\nconst HOMEPAGE_QUERY = `query HomePage($limit: Int) {\n  users(limit: $limit) {\n    id\n    name\n  }\n}`\n\nfunction MyComponent() {\n  const { loading, error, data } = useQuery(HOMEPAGE_QUERY, {\n    variables: {\n      limit: 10\n    }\n  })\n\n  if (loading) return 'Loading...'\n  if (error) return 'Something Bad Happened'\n\n  return (\n    \u003cul\u003e\n      {data.users.map(({ id, name }) =\u003e (\n        \u003cli key={id}\u003e{name}\u003c/li\u003e\n      ))}\n    \u003c/ul\u003e\n  )\n}\n```\n\n## Why `graphql-hooks`?\n\nThe first thing you may ask when seeing `graphql-hooks` is \"Why not use Apollo hooks?\".\nIt's the comparison most will make. In fact, there's an [article comparing the two](https://blog.logrocket.com/comparing-hooks-libraries-for-graphql/) over on LogRocket.\n\nWe believe `graphql-hooks` is a great choice as a hooks-first GraphQL client due to its concise API and package size.\n\nIn terms of performance, this is more of a grey area as we have no official benchmarks yet.\n\nIf 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.\n\n| Pros                        | Cons                                  |\n| --------------------------- | ------------------------------------- |\n| Small in size               | Less \"advanced\" caching configuration |\n| Concise API                 |\n| Quick to get up and running |\n\n# Table of Contents\n\n- API\n  - [GraphQLClient](#GraphQLClient)\n  - [ClientContext](#ClientContext)\n  - [useQuery](#useQuery)\n  - [useManualQuery](#useManualQuery)\n  - [useMutation](#useMutation)\n  - [useSubscription](#useSubscription)\n- Guides\n  - [SSR](#SSR)\n  - [Pagination](#Pagination)\n  - [File uploads](#File-uploads)\n  - [HTTP Get Support](#HTTP-Get-support)\n  - [Authentication](#Authentication)\n  - [Fragments](#Fragments)\n  - [Migrating from Apollo](#Migrating-from-Apollo)\n    - [ApolloClient ➡️ GraphQLClient](#apolloclient-️-graphqlclient)\n    - [ApolloProvider ➡️ ClientContext.Provider](#apolloprovider-️-clientcontextprovider)\n    - [Query Component ➡️ useQuery](#query-component-️-usequery)\n    - [Mutation Component ➡️ useMutation](#mutation-component-️-usemutation)\n  - [Testing and mocking](#testing-and-mocking)\n  - [Typescript Support](#typescript-support)\n  - [Other]\n    - [Request interceptors](#request-interceptors)\n    - [AbortController](#abortController)\n    - [GraphQL document support](#graphql-document-support)\n\n## API\n\n## `GraphQLClient`\n\n**Usage**:\n\n```js\nimport { GraphQLClient } from 'graphql-hooks'\nconst client = new GraphQLClient(config)\n```\n\n**`config`**: Object containing configuration properties\n\n- `url`: The URL of your GraphQL **HTTP** server. If not specified, you must enable `fullWsTransport` and provide a valid `subscriptionClient`; otherwise is **required**.\n- `fullWsTransport`: Boolean - set to `true` if you want to use `subscriptionClient` to also send query and mutations via WebSocket; defaults to `false`\n- `ssrMode`: Boolean - set to `true` when using on the server for server-side rendering; defaults to `false`\n- `useGETForQueries`: Boolean - set to `true` to use HTTP GET method for all queries; defaults to false. See [HTTP Get Support](#HTTP-Get-support) for more info\n- `subscriptionClient`: The **WebSocket** client configuration. Accepts either an instance of `SubscriptionClient` from [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) or `Client` from [graphql-ws](https://github.com/enisdenjo/graphql-ws). A factory function is also accepted e.g. to avoid the creation of the client in SSR environments.\n- `cache` (**Required** if `ssrMode` is `true`, otherwise optional): Object with the following methods:\n  - `cache.get(key)`\n  - `cache.set(key, data)`\n  - `cache.delete(key)`\n  - `cache.clear()`\n  - `cache.keys()`\n  - `getInitialState()`\n  - See [graphql-hooks-memcache](packages/graphql-hooks-memcache) as a reference implementation\n- `fetch(url, options)`: Fetch implementation - defaults to the global `fetch` API. Check [Request interceptors](#request-interceptors) for more details how to manage `fetch`.\n- `FormData`: FormData implementation - defaults to the global `FormData` API. Polyfill this in a node.js environment. See [file-uploads-nodejs](#file-uploads-nodejs) for more info.\n- `fetchOptions`: See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch) for info on what options can be passed\n- `headers`: Object, e.g. `{ 'My-Header': 'hello' }`\n- `logErrors`: Boolean - defaults to `true`\n- `middleware`: Accepts an array of middleware functions, default: none, see more in [middlewares readme](packages/graphql-hooks/src/middlewares/README.md)\n- `onError({ operation, result })`: Custom error handler\n  - `operation`: Object with `query`, `variables` and `operationName`\n  - `result`: Object containing `data`, `headers` and `error` object that contains `fetchError`, `httpError` and `graphqlErrors`\n\n### `client` methods\n\n- `client.setHeader(key, value)`: Updates `client.headers` adding the new header to the existing headers\n- `client.setHeaders(headers)`: Replaces `client.headers`\n- `client.removeHeader(key)`: Updates `client.headers` removing the header if it exists\n- `client.logErrorResult({ operation, result })`: Default error logger; useful if you'd like to use it inside your custom `onError` handler\n- `request(operation, options)`: Make a request to your GraphQL server; returning a Promise\n  - `operation`: Object with `query`, `variables` and `operationName`\n- `options.fetchOptionsOverrides`: Object containing additional fetch options to be added to the default ones passed to `new GraphQLClient(config)`\n- `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) =\u003e ({...data, myKey: response.headers.get('content-length)})`\n- `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 value\n  - `query`: The GraphQL query as a plain string to be re-fetched, or an Operation object (with `query`, `variables` and `operationName`)\n- `client.setQueryData(query, (oldState) =\u003e [...oldState, newState]])`: Will override the older cache state with the new one provided by the function return\n  - `query`: The GraphQL query as a plain string, or an Operation object (with `query`, `variables` and `operationName`)\n  - `(oldState) =\u003e [...oldState, newState]]`: The callback function with returns will be the new state stored in the cache.\n    - `oldState`: The old value stored in the cache\n\n## `ClientContext`\n\n`ClientContext` is the result of `React.createContext()` - meaning it can be used directly with React's new context API:\n\n**Example**:\n\n```js\nimport { ClientContext } from 'graphql-hooks'\n\nfunction App() {\n  return (\n    \u003cClientContext.Provider value={client}\u003e\n      {/* children can now consume the client context */}\n    \u003c/ClientContext.Provider\u003e\n  )\n}\n```\n\nTo access the `GraphQLClient` instance, call `React.useContext(ClientContext)`:\n\n```js\nimport React, { useContext } from 'react'\nimport { ClientContext } from 'graphql-hooks'\n\nfunction MyComponent() {\n  const client = useContext(ClientContext)\n}\n```\n\n## `useQuery`\n\n**Usage**:\n\n```js\nconst state = useQuery(query, [options])\n```\n\n**Example:**\n\n```js\nimport { useQuery } from 'graphql-hooks'\n\nfunction MyComponent() {\n  const { loading, error, data } = useQuery(query)\n\n  if (loading) return 'Loading...'\n  if (error) return 'Something bad happened'\n\n  return \u003cdiv\u003e{data.thing}\u003c/div\u003e\n}\n```\n\nThis 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.\n\n- `query`: Your GraphQL query as a plain string or DocumentNode\n- `options`: Object with the following optional properties\n  - `variables`: Object e.g. `{ limit: 10 }`\n  - `operationName`: If your query has multiple operations, pass the name of the operation you wish to execute.\n  - `persisted`: Boolean - defaults to `false`; Pass `true` if your graphql server supports `persisted` flag to serve persisted queries.\n  - `useCache`: Boolean - defaults to `true`; cache the query result\n  - `skip`: Boolean - defaults to `false`; do not execute the query if set to `true`\n  - `skipCache`: 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 automatically\n  - `ssr`: Boolean - defaults to `true`. Set to `false` if you wish to skip this query during SSR\n  - `fetchOptionsOverrides`: Object - Specific overrides for this query. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch) for info on what options can be passed\n  - `updateData(previousData, data)`: Function - Custom handler for merging previous \u0026 new query results; return value will replace `data` in `useQuery` return value\n    - `previousData`: Previous GraphQL query or `updateData` result\n    - `data`: New GraphQL query result\n  - `client`: GraphQLClient - If a GraphQLClient is explicitly passed as an option, then it will be used instead of the client from the `ClientContext`.\n  - `refetchAfterMutations`: String | Object | (String | Object)[] - You can specify when a mutation should trigger query refetch.\n    - If it's a string, it's the mutation string\n    - If it's an object then it has properties mutation and filter\n      - `mutation`: String - The mutation string\n      - `refetchOnMutationError`: boolean (optional, defaults to `true`) - It indicates whether the query must be re-fetched if the mutation returns an error\n      - `filter`: Function (optional) - It receives mutation's variables as parameter and blocks refetch if it returns false\n    - If it's an array, the elements can be of either type above\n\n### `useQuery` return value\n\n```js\nconst { loading, error, data, refetch, cacheHit } = useQuery(QUERY)\n```\n\n- `loading`: Boolean - `true` if the query is in flight\n- `data`: Object - the result of your GraphQL query\n- `headers`: Object - response headers\n- `refetch(options)`: Function - useful when refetching the same query after a mutation; NOTE this presets `skipCache=true` \u0026 will bypass the `options.updateData` function that was passed into `useQuery`. You can pass a new `updateData` into `refetch` if necessary.\n  - `options`: Object - options that will be merged into the `options` that were passed into `useQuery` (see above).\n- `cacheHit`: Boolean - `true` if the query result came from the cache, useful for debugging\n- `error`: Object - Set if at least one of the following errors has occurred and contains:\n  - `fetchError`: Object - Set if an error occurred during the `fetch` call\n  - `httpError`: Object - Set if an error response was returned from the server\n  - `graphQLErrors`: Array - Populated if any errors occurred whilst resolving the query\n\n## `useManualQuery`\n\nUse this when you don't want a query to automatically be fetched or wish to call a query programmatically.\n\n**Usage**:\n\n```js\nconst [queryFn, state] = useManualQuery(query, [options])\n```\n\n**Example**:\n\n```js\nimport { useManualQuery } from 'graphql-hooks'\n\nfunction MyComponent(props) {\n  const [fetchUser, { loading, error, data }] = useManualQuery(GET_USER_QUERY, {\n    variables: { id: props.userId }\n  })\n\n  return (\n    \u003cdiv\u003e\n      \u003cbutton onClick={fetchUser}\u003eGet User!\u003c/button\u003e\n      {error \u0026\u0026 \u003cdiv\u003eFailed to fetch user\u003cdiv\u003e}\n      {loading \u0026\u0026 \u003cdiv\u003eLoading...\u003c/div\u003e}\n      {data \u0026\u0026 \u003cdiv\u003eHello ${data.user.name}\u003c/div\u003e}\n    \u003c/div\u003e\n  )\n}\n```\n\nIf 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:\n\n```js\nimport { useManualQuery } from 'graphql-hooks'\n\nfunction MyComponent(props) {\n  const [fetchUser] = useManualQuery(GET_USER_QUERY)\n\n  const fetchUserThenSomething = async () =\u003e {\n    const user = await fetchUser({\n      variables: { id: props.userId }\n    })\n    return somethingElse()\n  }\n\n  return (\n    \u003cdiv\u003e\n      \u003cbutton onClick={fetchUserThenSomething}\u003eGet User!\u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n## `useQueryClient`\n\nWill return the graphql client provided to `ClientContext.Provider` as `value`\n\n**Usage**:\n\n```js\nconst client = useQueryClient()\n```\n\n**Example**:\n\n```js\nimport { useQueryClient } from 'graphql-hooks'\n\nfunction MyComponent() {\n  const client = useQueryClient()\n\n  return \u003cdiv\u003e...\u003c/div\u003e\n}\n```\n\n## `useMutation`\n\nMutations unlike Queries are not cached.\n\n**Usage**:\n\n```js\nconst [mutationFn, state, resetFn] = useMutation(mutation, [options])\n```\n\n**Example**:\n\n```js\nimport { useMutation } from 'graphql-hooks'\n\nconst UPDATE_USER_MUTATION = `mutation UpdateUser(id: String!, name: String!) {\n  updateUser(id: $id, name: $name) {\n    name\n  }\n}`\n\nfunction MyComponent({ id, name }) {\n  const [updateUser] = useMutation(UPDATE_USER_MUTATION)\n  const [newName, setNewName] = useState(name)\n\n  return (\n    \u003cdiv\u003e\n      \u003cinput\n        type=\"text\"\n        value={newName}\n        onChange={e =\u003e setNewName(e.target.value)}\n      /\u003e\n      \u003cbutton\n        onClick={() =\u003e updateUser({ variables: { id, name: newName } })}\n      /\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\nThe `options` object that can be passed either to `useMutation(mutation, options)` or `mutationFn(options)` can be set with the following properties:\n\n- `variables`: Object e.g. `{ limit: 10 }`\n- `operationName`: If your query has multiple operations, pass the name of the operation you wish to execute.\n- `fetchOptionsOverrides`: Object - Specific overrides for this query. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch) for info on what options can be passed\n- `client`: GraphQLClient - If a GraphQLClient is explicitly passed as an option, then it will be used instead of the client from the `ClientContext`.\n- `onSuccess`: A function to be called after the mutation has been finished with success without raising any error\n\nIn addition, there is an option to reset the current state before calling the mutation again, by calling `resetFn(desiredState)` where `desiredState` is optional and if passed, it will override the initial state with:\n\n- `data`: Object - the data\n- `headers`: Object - response headers\n- `error`: Error - the error\n- `loading`: Boolean - true if it is still loading\n- `cacheHit`: Boolean - true if the result was cached\n\n## `useSubscription`\n\nTo use subscription you can use either [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) or [graphql-ws](https://github.com/enisdenjo/graphql-ws)\n\n**API**\n\n`useSubscription(operation, callback)`\n\n- `operation`: Object - The GraphQL operation has the following properties:\n  - `query`: String (required) - the GraphQL query\n  - `variables`: Object (optional) - Any variables the query might need\n  - `operationName`: String (optional) - If your query has multiple operations, you can choose which operation you want to call.\n  - `client`: GraphQLClient - If a GraphQLClient is explicitly passed as an option, then it will be used instead of the client from the `ClientContext`.\n  - `skip`: Boolean (optional) - If true, the subscription will not be created.\n- `callback`: Function - This will be invoked when the subscription receives an event from your GraphQL server - it will receive an object with the typical GraphQL response of `{ data: \u003cyour result\u003e, errors?: [Error] }`\n\n**Usage**:\n\nFirst, follow the [quick start guide](#Quick-Start) to create the client and provider. Then we need to update the config for our `GraphQLClient` passing in the `subscriptionClient`:\n\n```js\nimport { GraphQLClient } from 'graphql-hooks'\nimport { SubscriptionClient } from 'subscriptions-transport-ws'\n// or\nimport { createClient } from 'graphql-ws'\n\nconst client = new GraphQLClient({\n  url: 'http://localhost:8000/graphql',\n  subscriptionClient: () =\u003e\n    new SubscriptionClient('ws://localhost:8000/graphql', {\n      /* additional config options */\n    }),\n  // or\n  subscriptionClient: () =\u003e\n    createClient({\n      url: 'ws://localhost:8000/graphql'\n      /* additional config options */\n    })\n})\n```\n\nNext, within our React app, we can now make use of the `useSubscription` hook.\n\n```js\nimport React, { useState } from 'react'\nimport { useSubscription } from 'graphql-hooks'\n\nconst TOTAL_COUNT_SUBSCRIPTION = `\n  subscription TotalCount {\n    totalCount {\n      count\n    }\n  }\n`\n\nfunction TotalCountComponent() {\n  const [count, setCount] = useState(0)\n  const [error, setError] = useState(null)\n\n  useSubscription({ query: TOTAL_COUNT_SUBSCRIPTION }, ({ data, errors }) =\u003e {\n    if (errors \u0026\u0026 errors.length \u003e 0) {\n      // handle your errors\n      setError(errors[0])\n      return\n    }\n\n    // all good, handle the gql result\n    setCount(data.totalCount.count)\n  })\n\n  if (error) {\n    return \u003cspan\u003eAn error occurred {error.message}\u003c/span\u003e\n  }\n\n  return \u003cdiv\u003eCurrent count: {count}\u003c/div\u003e\n}\n```\n\n**Working Example**:\n\nSee our [subscription example](examples/subscription) which has both the client and server code to integrate subscriptions into your application.\n\nSee also the [full WS transport example](examples/full-ws-transport) if you want to see how to send every operation through WebSocket.\n\n# Guides\n\n## SSR\n\nSee [graphql-hooks-ssr](packages/graphql-hooks-ssr) for an in depth guide.\n\n## Pagination\n\n[GraphQL Pagination](https://graphql.org/learn/pagination/) can be implemented in various ways and it's down to the consumer to decide how to deal with the resulting data from paginated queries. Take the following query as an example of offset pagination:\n\n```javascript\nexport const allPostsQuery = `\n  query allPosts($first: Int!, $skip: Int!) {\n    allPosts(first: $first, skip: $skip) {\n      id\n      title\n      url\n    }\n    _allPostsMeta {\n      count\n    }\n  }\n`\n```\n\nIn this query, the `$first` variable is used to limit the number of posts that are returned and the `$skip` variable is used to determine the offset at which to start. We can use these variables to break up large payloads into smaller chunks, or \"pages\". We could then choose to display these chunks as distinct pages to the user, or use an infinite loading approach and append each new chunk to the existing list of posts.\n\n### Separate pages\n\nHere is an example where we display the paginated queries on separate pages:\n\n```jsx\nimport { React, useState } from 'react'\nimport { useQuery } from 'graphql-hooks'\n\nexport default function PostList() {\n  // set a default offset of 0 to load the first page\n  const [skipCount, setSkipCount] = useState(0)\n\n  const { loading, error, data } = useQuery(allPostsQuery, {\n    variables: { skip: skipCount, first: 10 }\n  })\n\n  if (error) return \u003cdiv\u003eThere was an error!\u003c/div\u003e\n  if (loading \u0026\u0026 !data) return \u003cdiv\u003eLoading\u003c/div\u003e\n\n  const { allPosts, _allPostsMeta } = data\n  const areMorePosts = allPosts.length \u003c _allPostsMeta.count\n\n  return (\n    \u003csection\u003e\n      \u003cul\u003e\n        {allPosts.map(post =\u003e (\n          \u003cli key={post.id}\u003e\n            \u003ca href={post.url}\u003e{post.title}\u003c/a\u003e\n          \u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n      \u003cbutton\n        // reduce the offset by 10 to fetch the previous page\n        onClick={() =\u003e setSkipCount(skipCount - 10)}\n        disabled={skipCount === 0}\n      \u003e\n        Previous page\n      \u003c/button\u003e\n      \u003cbutton\n        // increase the offset by 10 to fetch the next page\n        onClick={() =\u003e setSkipCount(skipCount + 10)}\n        disabled={!areMorePosts}\n      \u003e\n        Next page\n      \u003c/button\u003e\n    \u003c/section\u003e\n  )\n}\n```\n\n### Infinite loading\n\nHere is an example where we append each paginated query to the bottom of the current list:\n\n```jsx\nimport { React, useState } from 'react'\nimport { useQuery } from 'graphql-hooks'\n\n// use options.updateData to append the new page of posts to our current list of posts\nconst updateData = (prevData, data) =\u003e ({\n  ...data,\n  allPosts: [...prevData.allPosts, ...data.allPosts]\n})\n\nexport default function PostList() {\n  const [skipCount, setSkipCount] = useState(0)\n\n  const { loading, error, data } = useQuery(allPostsQuery, {\n    variables: { skip: skipCount, first: 10 },\n    updateData\n  })\n\n  if (error) return \u003cdiv\u003eThere was an error!\u003c/div\u003e\n  if (loading \u0026\u0026 !data) return \u003cdiv\u003eLoading\u003c/div\u003e\n\n  const { allPosts, _allPostsMeta } = data\n  const areMorePosts = allPosts.length \u003c _allPostsMeta.count\n\n  return (\n    \u003csection\u003e\n      \u003cul\u003e\n        {allPosts.map(post =\u003e (\n          \u003cli key={post.id}\u003e\n            \u003ca href={post.url}\u003e{post.title}\u003c/a\u003e\n          \u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n      {areMorePosts \u0026\u0026 (\n        \u003cbutton\n          // set the offset to the current number of posts to fetch the next page\n          onClick={() =\u003e setSkipCount(allPosts.length)}\n        \u003e\n          Show more\n        \u003c/button\u003e\n      )}\n    \u003c/section\u003e\n  )\n}\n```\n\n## Refetch queries with mutations subscription\n\nWe can have a query to automatically refetch when any mutation from a provided list is executed.\nIn the following example we are refetching a list of posts for a given user.\n\n**Example**\n\n```jsx\nexport const allPostsByUserIdQuery = `\n  query allPosts($userId: Int!) {\n    allPosts(userId: $userId) {\n      id\n      title\n      url\n    }\n  }\n`\n\nexport const createPostMutation = `\n  mutation createPost($userId: Int!, $text: String!) {\n    createPost(userId: $userId, text: $text) {\n      id\n      title\n      url\n    }\n  }\n`\n\nconst myUserId = 5\n\nuseQuery(allPostsByUserIdQuery, {\n  variables: {\n    userId: myUserId\n  },\n  refetchAfterMutations: [\n    {\n      mutation: createPostMutation,\n      filter: variables =\u003e variables.userId === myUserId\n    }\n  ]\n})\n```\n\n## Manually updating the cache after some mutation\n\nThere are two ways to reach that:\n\n### By re-fetching the query\n\n```js\nimport { useMutation, useQueryClient } from 'graphql-hooks'\nimport React from 'react'\n\nconst MY_MUTATION = `...`\nconst MY_QUERY = `...`\n\nexport default function MyComponent() {\n  const client = useQueryClient()\n  const [applyMutation, { ... }] = useMutation(MY_MUTATION, {\n    onSuccess: () =\u003e client.invalidateQuery(MY_QUERY)\n  })\n\n  return (\n    ...\n  )\n}\n```\n\n### By overriding the old state in the cache without re-fetching data\n\n```js\nimport { useMutation, useQueryClient } from 'graphql-hooks'\nimport React from 'react'\n\nconst MY_MUTATION = `...`\nconst MY_QUERY = `...`\n\nexport default function MyComponent() {\n  const client = useQueryClient()\n  const [applyMutation, { ... }] = useMutation(MY_MUTATION, {\n    onSuccess: (result) =\u003e {\n      client.setQueryData(MY_QUERY, oldState =\u003e [\n        ...oldState,\n        result,\n      ])\n    }\n  })\n\n  return (\n    ...\n  )\n}\n```\n\n## File uploads\n\n`graphql-hooks` complies with the [GraphQL multipart request spec](https://github.com/jaydenseric/graphql-multipart-request-spec), allowing files to be used as query or mutation arguments. The same spec is also supported by popular GraphQL servers, including [Apollo Server](https://www.apollographql.com/docs/apollo-server) (see list of supported servers [here](https://github.com/jaydenseric/graphql-multipart-request-spec#server)).\n\nIf there are files to upload, the request's body will be a [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData) instance conforming to the GraphQL multipart request spec.\n\n```jsx\nimport React, { useRef } from 'react'\nimport { useMutation } from 'graphql-hooks'\n\nconst uploadPostPictureMutation = `\n  mutation UploadPostPicture($picture: Upload!) {\n    uploadPostPicture(picture: $picture) {\n      id\n      pictureUrl\n    }\n  }\n`\n\nexport default function PostForm() {\n  // File input is always uncontrolled in React.\n  // See: https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag.\n  const fileInputRef = useRef(null)\n\n  const [uploadPostPicture] = useMutation(uploadPostPictureMutation)\n\n  const handleSubmit = event =\u003e {\n    event.preventDefault()\n\n    uploadPostPicture({\n      variables: {\n        picture: fileInputRef.current.files[0]\n      }\n    })\n  }\n\n  return (\n    \u003cform onSubmit={handleSubmit}\u003e\n      \u003cinput accept=\"image/*\" ref={fileInputRef} type=\"file\" /\u003e\n      \u003cbutton\u003eUpload\u003c/button\u003e\n    \u003c/form\u003e\n  )\n}\n```\n\n### File uploads Node.js\n\n```js\nimport { FormData } from 'formdata-node'\nimport { fileFromPath } from 'formdata-node/file-from-path'\n\nconst client = new GraphQLClient({\n  url: 'https://domain.com/graphql',\n  fetch: require('node-fetch'),\n  FormData\n})\n\nconst uploadPostPictureMutation = `\n  mutation UploadPostPicture($picture: Upload!) {\n    uploadPostPicture(picture: $picture) {\n      id\n      pictureUrl\n    }\n  }\n`\n\nconst { data, error } = await client.request({\n  query: uploadPostPictureMutation,\n  variables: { picture: await fileFromPath('some-file.txt') }\n})\n```\n\n## HTTP Get support\n\nUsing `GET` for queries can be useful, especially when implementing any sort of HTTP caching strategy. There are two ways you can do this:\n\n**Per Query**\n\n```js\nconst { loading, error, data } = useQuery(MY_QUERY, {\n  fetchOptionsOverrides: { method: 'GET' }\n})\n\n// same goes for useManualQuery\nconst [fetchSomething] = useManualQuery(MY_QUERY, {\n  fetchOptionsOverrides: { method: 'GET' }\n})\n```\n\n**For All Queries**\n\nWhen you create your client, set the `useGETForQueries` option as `true`:\n\n```js\nconst client = new GraphQLClient({\n  url: '/graphql',\n  useGETForQueries: true\n})\n```\n\n## Authentication\n\nYou can have access to the graphql-hooks client context by using React's new context API. `ClientContext` is actually the result of `React.createContext()`.\n\n**Login Example**\n\n```jsx\nimport React, { useState, useContext } from 'react'\nimport { useMutation, ClientContext } from 'graphql-hooks'\n\nconst LOGIN_MUTATION = `mutation LoginUser (name: String!, password: String!) {\n  loginUser(name: $name, password: $password) {\n    token\n  }\n}`\n\nconst Login = () =\u003e {\n  const client = useContext(ClientContext)\n  const [loginUserMutation] = useMutation(LOGIN_MUTATION)\n  const [userName, setUserName] = useState()\n  const [password, setPassword] = useState()\n\n  const handleLogin = async e =\u003e {\n    e.preventDefault()\n    const { data, error } = await loginUserMutation({\n      variables: { userName, password }\n    })\n    if (error) {\n      // your code to handle login error\n    } else {\n      const { token } = data.loginUser\n      client.setHeader('Authorization', `Bearer ${token}`)\n      // your code to handle token in browser and login redirection\n    }\n  }\n  return (\n    \u003cform onSubmit={handleLogin}\u003e\n      User Name:{' '}\n      \u003cinput\n        type={'text'}\n        value={userName}\n        onChange={e =\u003e setUserName(e.target.value)}\n      /\u003e\n      PassWord: \u003cinput\n        type={'password'}\n        value={password}\n        onChange={e =\u003e setPassword(e.target.value)}\n      /\u003e\n      \u003cinput type={'submit'} value={'Login'} /\u003e\n    \u003c/form\u003e\n  )\n}\n\nexport default Login\n```\n\nIn the above example we use `useContext()` hook to get access to the graphql-hooks clientContext.\nThen we request the token from the server by performing the `loginUser` mutation.\nIn the case the login is successful we set the token to the client's header (`client.setHeader`), otherwise we need to handle the error.\nFor more information about graphql-hooks clientContext refer to [GraphQLClient](#GraphQLClient) section.\n\n## Fragments\n\nComing soon!\n\n## Migrating from Apollo\n\nFor a real life example, compare the next.js [with-apollo](https://github.com/zeit/next.js/tree/canary/examples/with-apollo) vs [with-graphql-hooks](https://github.com/zeit/next.js/tree/canary/examples/with-graphql-hooks). We have feature parity and the `main-*.js` bundle is a whopping **93% smaller** (7.9KB vs 116KB).\n\n### ApolloClient ➡️ GraphQLClient\n\n```diff\n- import { ApolloClient } from 'apollo-client'\n- import { InMemoryCache } from 'apollo-cache-inmemory'\n+ import { GraphQLClient } from 'graphql-hooks'\n+ import memCache from 'graphql-hooks-memcache'\n\n- const client = new ApolloClient({\n-  uri: '/graphql',\n-  cache: new InMemoryCache()\n- })\n+ const client = new GraphQLClient({\n+   url: '/graphql',\n+   cache: memCache()\n+ })\n```\n\nA lot of the options you'd pass to `ApolloClient` are the same as `GraphQLClient`:\n\n- `uri` ➡️ `url`\n- `fetchOptions`\n- `onError` - the function signature is slightly different\n- `headers`\n- `fetch`\n- `cache`\n\n### ApolloProvider ➡️ ClientContext.Provider\n\n```diff\n- import { ApolloProvider } from 'react-apollo'\n+ import { ClientContext } from 'graphql-hooks'\n\nfunction App({ client }) {\n  return (\n-    \u003cApolloProvider client={client}\u003e\n+    \u003cClientContext.Provider value={client}\u003e\n       {/* children */}\n+    \u003c/ClientContext.Provider\u003e\n-    \u003c/ApolloProvider\u003e\n  )\n}\n```\n\n### Query Component ➡️ useQuery\n\n```diff\n- import { Query } from 'react-apollo'\n- import gql from 'graphql-tag'\n+ import { useQuery } from 'graphql-hooks'\n\nfunction MyComponent() {\n+ const { loading, error, data } = useQuery('...')\n\n-  return (\n-    \u003cQuery query={gql`...`}\u003e\n-     {({ loading, error, data}) =\u003e {\n        if (loading) return 'Loading...'\n        if (error) return 'Error :('\n\n        return \u003cdiv\u003e{data}\u003c/div\u003e\n-      }}\n-    \u003c/Query\u003e\n-  )\n}\n```\n\n### Query Component Props\n\nA lot of options can be carried over as-is, or have direct replacements:\n\n- `query` ➡️ `useQuery(query)`: Remove any usage of `gql` and pass your queries as strings.\n- `variables` ➡️ `useQuery(query, { variables })`\n- `ssr` ➡️ `useQuery(query, { ssr })`\n- **Fetch Policies**: See [#75](https://github.com/nearform/graphql-hooks/issues/75) for more info\n  - `cache-first`: This is the default behaviour of `graphql-hooks`\n  - `cache-and-network`: The refetch function provides this behavior it will set loading: true, but the old data will be still set until the fetch resolves.\n  - `network-only` ➡️ `useQuery(QUERY, { skipCache: true })`\n  - `cache-only`: Not supported\n  - `no-cache` ➡️ `useQuery(QUERY, { useCache: false })`\n\n**Not yet supported**\n\n- `errorPolicy`: Any error will set the `error` to be truthy. See [useQuery](#useQuery) for more details.\n- `pollInterval`\n- `notifyOnNetworkStatusChange`\n- `skip`\n- `onCompleted`: Similar ability if using `useManualQuery`\n- `onError`: Similar ability if using `useManualQuery`\n- `partialRefetch`\n\n### Query Component Render Props\n\n```diff\n- \u003cQuery query={gql`...`}\u003e\n-  {(props) =\u003e {}}\n- \u003c/Query\u003e\n+ const state = useQuery(`...`)\n```\n\n- `props.loading` ➡️ `const { loading } = useQuery('...')`\n- `props.error` ➡️ `const { error } = useQuery('...')`: The error value from `useQuery` is Boolean the details of the error can be found in either:\n  - `state.fetchError`\n  - `state.httpError`\n  - `state.graphQLErrors`\n- `props.refetch` ️➡️ `const { refetch } = useQuery('...')`\n- `props.updateData(prevResult, options)` ️➡️ `state.updateData(prevResult, newResult)`\n\n**Not yet supported**\n\n- `props.networkStatus`\n- `props.startPolling`\n- `props.stopPolling`\n- `props.subscribeToMore`\n\n### Mutation Component ➡️ useMutation\n\n```diff\n- import { Mutation } from 'react-apollo'\n- import gql from 'graphql-tag'\n+ import { useMutation } from 'graphql-hooks'\n\nfunction MyComponent() {\n+ const [mutateFn, { loading, error, data }] = useMutation('...')\n\n-  return (\n-    \u003cMutation mutation={gql`...`}\u003e\n-     {(mutateFn, { loading, error }) =\u003e {\n        if (error) return 'Error :('\n\n        return \u003cbutton disabled={loading} onClick={() =\u003e mutateFn()}\u003eSubmit\u003c/button\u003e\n-      }}\n-    \u003c/Mutation\u003e\n-  )\n}\n```\n\n### Mutation Props\n\n- `mutation` ➡️ `useMutation(mutation)` - no need to wrap it in `gql`\n- `variables` ➡️️ `useMutation(mutation, { variables })` or `mutateFn({ variables })`\n- `ignoreResults` ➡️️️️ `const [mutateFn] = useMutation(mutation)`\n- `onCompleted` ➡️ ️`mutateFn().then(onCompleted)`\n- `onError` ➡️ `mutateFn().then(({ error }) =\u003e {...})`\n\n**Not yet supported**\n\n- `update`: Coming soon [#52](https://github.com/nearform/graphql-hooks/issues/52)\n- `optimisticResponse`\n- `refetchQueries`\n- `awaitRefetchQueries`\n- `context`\n\n## Mutation Component Render Props\n\n```diff\n- \u003cMutation mutation={gql`...`}\u003e\n-  {(mutateFn, props) =\u003e {}}\n- \u003c/Mutation\u003e\n+ const [mutateFn, state] = useMutation(`...`)\n```\n\n- `props.data` ➡️ `const [mutateFn, { data }] = useMutation()`\n- `props.loading` ➡️ `const [mutateFn, { loading }] = useMutation()`\n- `props.error` ➡️ `const [mutateFn, { error }] = useMutation()`: The the details of the error can be found in either:\n  - `state.fetchError`\n  - `state.httpError`\n  - `state.graphQLErrors`\n- `client` ️➡️️ `const client = useContext(ClientContext)` see [ClientContext](#ClientContext)\n\n**Not yet supported**\n\n- `called`\n\n## Testing and mocking\n\nThere is a `LocalGraphQLClient` class you can use to mock requests without a server for testing or development purposes.\n\nThis client inherits from `GraphQLClient` and provides the same API, but doesn't connect to any server and instead responds to pre-defined queries.\n\nIt needs to be supplied on creation with a `localQueries` object, which is an object where:\n\n- the keys are the queries defined in the application;\n- the values are query functions returning the mocked data.\n\n```js\n// src/components/Post.js\nexport const allPostsQuery = `\n  query {\n    allPosts {\n      id\n      title\n      url\n    }\n  }\n`\n```\n\n```js\n// test/Post.test.tsx\nimport { allPostsQuery, createPostMutation } from '../src/components/Post'\n\nconst localQueries = {\n  [allPostsQuery]: () =\u003e ({\n    allPosts: [\n      {\n        id: 1,\n        title: 'Test',\n        url: 'https://example.com'\n      }\n    ]\n  }),\n  [createPostMutation]: () =\u003e ({ createPost: { id: 1 } })\n}\nconst client = new LocalGraphQLClient({ localQueries })\nconst { data, error } = await client.request({\n  query: allPostsQuery\n})\n```\n\nThe `LocalGraphQLClient` will return `data` and `error` properties in the same format as the `GraphQLClient`\n\n### Variables\n\nVariables can be used in the local mock queries given to the `LocalGraphQLClient`, which can then be supplied to the `request` function:\n\n```js\nconst localQueries = {\n  AddNumbersQuery: ({ a, b }) =\u003e ({\n    addedNumber: a + b\n  })\n}\nconst client = new LocalGraphQLClient({ localQueries })\nconst result = await client.request({\n  query: 'AddNumbersQuery',\n  variables: {\n    a: 2,\n    b: 3\n  }\n})\nconsole.log(result.data.addedNumber) // Will be 5\n```\n\n### Error mocking\n\nErrors can be simply mocked in `LocalGraphQLClient` queries by using the `LocalGraphQLError` class:\n\n```js\n// test/Post.test.tsx\nimport { allPostsQuery } from '../src/components/Post'\n\nconst localQueries = {\n  [allPostsQuery]: () =\u003e\n    new LocalGraphQLError({\n      httpError: {\n        status: 404,\n        statusText: 'Not found',\n        body: 'Not found'\n      }\n    })\n}\nconst client = new LocalGraphQLClient({ localQueries })\nconst result = await client.request({\n  query: allPostsQuery\n})\nconsole.log(result.error) // The `error` object will have an `httpError`\n```\n\nIt is also possible to mock a partial error response (for example where one resolver encounters an error but other resolvers return successfully). To do this, include `Error` objects in the mock query resolver:\n\n```js\nimport { allPostsQuery } from '../src/components/Post'\n\nconst localQueries = {\n  [allPostsQuery]: () =\u003e ({\n    field1: 'foo',\n    field2: new Error('something went wrong'),\n    nested: {\n      field3: new Error('a nested error')\n    }\n  })\n}\nconst client = new LocalGraphQLClient({ localQueries })\nconst result = await client.request({\n  query: allPostsQuery\n})\nconsole.log(result.data) // The `data` object will have the correct value for `field1` and `null` for any fields returning `Error` objects\nconsole.log(result.error) // The `error` object will have a `graphQLErrors` array containing each of the `Error` objects created above\n```\n\n### Testing with React\n\nExample tests that use the `LocalGraphQLClient` are provided in [the examples/create-react-app/test folder](https://github.com/nearform/graphql-hooks/blob/master/examples/create-react-app/test/Posts.test.tsx).\n\nThe [test-utils.tsx](https://github.com/nearform/graphql-hooks/blob/master/examples/create-react-app/test/test-utils.tsx) is a good example of how to create a custom render function using [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro/) which can wrap the render of a React component in a `ClientContext` setup to use the `LocalGraphQLClient` with supplied local queries:\n\n```js\nconst customRender = (ui, options) =\u003e {\n  const client = new LocalGraphQLClient({\n    localQueries: options.localQueries\n  })\n\n  const Wrapper = ({ children }) =\u003e {\n    return (\n      \u003cClientContext.Provider value={client}\u003e{children}\u003c/ClientContext.Provider\u003e\n    )\n  }\n\n  Wrapper.propTypes = {\n    children: T.node.isRequired\n  }\n\n  return render(ui, {\n    wrapper: Wrapper,\n    ...options\n  })\n}\n\nexport * from '@testing-library/react'\n\nexport { customRender as render }\n```\n\nUsing this allows us to easily render a component using the `LocalGraphQLClient` with local queries when writing tests:\n\n```js\n// Comes from the above code\nimport { render, screen } from './test-utils'\n\nconst localQueries = {\n  [allPostsQuery]: () =\u003e ({\n    allPosts: [\n      {\n        id: 1,\n        title: 'Test',\n        url: 'https://example.com'\n      }\n    ]\n  })\n}\n\ndescribe('Posts', () =\u003e {\n  it('should render successfully', async () =\u003e {\n    render(\u003cPosts /\u003e, {\n      localQueries\n    })\n\n    expect(\n      await screen.findByRole('link', {\n        name: /Test/i\n      })\n    ).toBeTruthy()\n  })\n})\n```\n\n### Changing mock queries during tests\n\nBecause the `LocalGraphQLClient` just uses the `localQueries` object supplied to it, it is possible to modify or spy the local queries during tests. For example:\n\n```js\nit('shows \"No posts\" if 0 posts are returned', async () =\u003e {\n  jest.spyOn(localQueries, allPostsQuery).mockImplementation(() =\u003e ({\n    allPosts: []\n  }))\n\n  render(\u003cPosts /\u003e, {\n    localQueries\n  })\n\n  expect(await screen.findByText('No posts')).toBeTruthy()\n})\n```\n\n## Typescript Support\n\nAll client methods support the ability to provide type information for response data, query variables and error responses.\n\n```typescript\nimport { useQuery } from 'graphql-hooks'\n\ntype User = {\n  id: string\n  name: string\n}\n\ntype CustomError = {\n  message: string\n  extensions?: Record\u003cstring, any\u003e\n}\n\nconst HOMEPAGE_QUERY = `query HomePage($limit: Int) {\n  users(limit: $limit) {\n    id\n    name\n  }\n}`\n\nfunction MyComponent() {\n  const { loading, error, data } = useQuery\u003c\n    User,\n    { limit: number },\n    CustomError\n  \u003e(HOMEPAGE_QUERY, {\n    variables: {\n      limit: 10\n    }\n  })\n\n  if (loading) return 'Loading...'\n  if (error) return 'Something Bad Happened'\n\n  return (\n    \u003cul\u003e\n      {data.users.map(({ id, name }) =\u003e (\n        \u003cli key={id}\u003e{name}\u003c/li\u003e\n      ))}\n    \u003c/ul\u003e\n  )\n}\n```\n\n`graphql-hooks` also supports `TypedDocumentNode`. This allows you to use GraphQL code gen to create `DocumentNode`s for your GQL queries and receive full type support.\n\n```typescript\nimport { useQuery } from 'graphql-hooks'\nimport { graphql } from './gql'\n\nconst HOMEPAGE_QUERY = graphql(`query HomePage($limit: Int) {\n  users(limit: $limit) {\n    id\n    name\n  }\n}`)\n\nfunction MyComponent() {\n  // data will be typed as User objects with id, name properties\n  const { loading, error, data } = useQuery(HOMEPAGE_QUERY, {\n    variables: {\n      limit: 10\n    }\n  })\n\n  if (loading) return 'Loading...'\n  if (error) return 'Something Bad Happened'\n\n  return (\n    \u003cul\u003e\n      {data.users.map(({ id, name }) =\u003e (\n        \u003cli key={id}\u003e{name}\u003c/li\u003e\n      ))}\n    \u003c/ul\u003e\n  )\n}\n```\n\nFull details of the features of `TypedDocumentNode` and GraphQL Code Generator can be found [here](https://the-guild.dev/graphql/codegen). Full examples of this implementation are in the examples folder.\n\n\n## Other\n\n### Request interceptors\n\nIt is possible to provide a custom library to handle network requests. Having that there is more control on how to handle the requests. The following example shows how to supply axios HTTP client with interceptors. It can be handy in the situations where JWT token has expired, needs to be refreshed and request retried.\n\n```js\nimport axios from 'axios'\nimport { buildAxiosFetch } from '@lifeomic/axios-fetch'\nimport { GraphQLClient } from 'graphql-hooks'\n\nconst gqlAxios = axios.create()\ngqlAxios.interceptors.response.use(\n  function (response) {\n    return response\n  },\n  function (error) {\n    // Handle expired JWT and refresh token\n  }\n)\n\nconst client = new GraphQLClient({\n  url: '/graphql',\n  fetch: buildAxiosFetch(gqlAxios)\n})\n```\n\n### AbortController\n\nif you wish to abort a fetch it is possible to pass an AbortController signal to the `fetchOptionsOverrides` option of the fetch function. This is not `graphql-hooks` specific functionality, rather just an example of how to use it with the library.\n\n```js\nimport { useManualQuery } from 'graphql-hooks'\n\nfunction AbortControllerExample() {\n  const abortControllerRef = useRef()\n  const [fetchData, { loading }] = useManualQuery(`...`)\n\n  const handleFetch = () =\u003e {\n    abortControllerRef.current = new AbortController()\n    const { signal } = abortControllerRef.current\n    fetchData({\n      fetchOptionsOverrides: {\n        signal\n      }\n    })\n  }\n\n  const handleAbort = () =\u003e {\n    abortControllerRef.current?.abort()\n  }\n\n  return (\n    \u003c\u003e\n      \u003cbutton onClick={handleFetch}\u003eFetch Data\u003c/button\u003e\n      {loading \u0026\u0026 \u003cbutton onClick={handleAbort}\u003eAbort\u003c/button\u003e}\n    \u003c/\u003e\n  )\n}\n```\n\n### GraphQL Document Support\n\nAs well as supporting input of your queries as strings, this library also supports using a `DocumentNode`. Document nodes can be generated using a code-generation tool such as [GraphQL codegen](https://the-guild.dev/graphql/codegen) which will provide typing information for your queries based on your GraphQL schema (see the typescript example). If you don't want to use a code-generation library you can use `graphql-tag` to generate a `DocumentNode`.\n\n\n```js\nimport gql from 'graphql-tag'\n\nconst allPostsQuery = gql`\n  query {\n     posts {\n      id\n      name\n     }\n  }\n`\n\nfunction Posts() {\n  const { loading, error, data, refetch } = useQuery(allPostsQuery)\n\n  return (\n    \u003c\u003e\n      \u003ch2\u003eAdd post\u003c/h2\u003e\n      \u003cAddPost /\u003e\n      \u003ch2\u003ePosts\u003c/h2\u003e\n      \u003cbutton onClick={() =\u003e refetch()}\u003eReload\u003c/button\u003e\n      \u003cPostList loading={loading} error={error} data={data} /\u003e\n    \u003c/\u003e\n  )\n}\n\n...\n```\n\n## Community\n\nWe now use GitHub Discussions for our community. To join, click on [\"Discussions\"](https://github.com/nearform/graphql-hooks/discussions). We encourage you to start a new discussion, share some ideas or ask questions from the community.\nIf you want to see the old community posts (on Spectrum) you can access them [here](https://spectrum.chat/graphql-hooks).\n\n## Contributors\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://twitter.com/bmullan91\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/1939483?v=4?s=100\" width=\"100px;\" alt=\"Brian Mullan\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eBrian Mullan\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#question-bmullan91\" title=\"Answering Questions\"\u003e💬\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Abmullan91\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=bmullan91\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#content-bmullan91\" title=\"Content\"\u003e🖋\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=bmullan91\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#example-bmullan91\" title=\"Examples\"\u003e💡\u003c/a\u003e \u003ca href=\"#ideas-bmullan91\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#maintenance-bmullan91\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/pulls?q=is%3Apr+reviewed-by%3Abmullan91\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=bmullan91\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://jackdc.com\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/1485654?v=4?s=100\" width=\"100px;\" alt=\"Jack Clark\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJack Clark\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#question-jackdclark\" title=\"Answering Questions\"\u003e💬\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Ajackdclark\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=jackdclark\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#content-jackdclark\" title=\"Content\"\u003e🖋\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=jackdclark\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#example-jackdclark\" title=\"Examples\"\u003e💡\u003c/a\u003e \u003ca href=\"#ideas-jackdclark\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#maintenance-jackdclark\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/pulls?q=is%3Apr+reviewed-by%3Ajackdclark\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=jackdclark\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://twitter.com/joezo\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/2870255?v=4?s=100\" width=\"100px;\" alt=\"Joe Warren\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJoe Warren\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#question-Joezo\" title=\"Answering Questions\"\u003e💬\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3AJoezo\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=Joezo\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#content-Joezo\" title=\"Content\"\u003e🖋\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=Joezo\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#example-Joezo\" title=\"Examples\"\u003e💡\u003c/a\u003e \u003ca href=\"#ideas-Joezo\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#maintenance-Joezo\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/pulls?q=is%3Apr+reviewed-by%3AJoezo\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=Joezo\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://simoneb.github.io\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/20181?v=4?s=100\" width=\"100px;\" alt=\"Simone Busoli\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSimone Busoli\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#question-simoneb\" title=\"Answering Questions\"\u003e💬\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Asimoneb\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=simoneb\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://jheytompkins.com\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/842246?v=4?s=100\" width=\"100px;\" alt=\"jhey tompkins\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ejhey tompkins\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=jh3y\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"#question-jh3y\" title=\"Answering Questions\"\u003e💬\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Ajh3y\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=jh3y\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#content-jh3y\" title=\"Content\"\u003e🖋\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/pulls?q=is%3Apr+reviewed-by%3Ajh3y\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://haroen.me\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/6270048?v=4?s=100\" width=\"100px;\" alt=\"Haroen Viaene\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eHaroen Viaene\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3AHaroenv\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/aribouius\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/10748727?v=4?s=100\" width=\"100px;\" alt=\"Ari Bouius\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAri Bouius\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=aribouius\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Aaribouius\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=aribouius\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=aribouius\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/kkogovsek\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/8089644?v=4?s=100\" width=\"100px;\" alt=\"Klemen Kogovšek\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eKlemen Kogovšek\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Akkogovsek\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"#ideas-kkogovsek\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=kkogovsek\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=kkogovsek\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/wescoder\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/22945955?v=4?s=100\" width=\"100px;\" alt=\"Wésley Queiroz\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eWésley Queiroz\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Awescoder\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=wescoder\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://www.good-idea.studio\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/11514928?v=4?s=100\" width=\"100px;\" alt=\"Joseph Thomas\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJoseph Thomas\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Agood-idea\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=good-idea\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=good-idea\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://edvinasbartkus.lt\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/202988?v=4?s=100\" width=\"100px;\" alt=\"Edvinas Bartkus\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eEdvinas Bartkus\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=edvinasbartkus\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#question-edvinasbartkus\" title=\"Answering Questions\"\u003e💬\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Aedvinasbartkus\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=edvinasbartkus\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#example-edvinasbartkus\" title=\"Examples\"\u003e💡\u003c/a\u003e \u003ca href=\"#ideas-edvinasbartkus\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#maintenance-edvinasbartkus\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/pulls?q=is%3Apr+reviewed-by%3Aedvinasbartkus\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=edvinasbartkus\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/olistic\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/5600126?v=4?s=100\" width=\"100px;\" alt=\"Matías Olivera\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMatías Olivera\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Aolistic\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=olistic\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=olistic\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=olistic\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/tcudok-jg\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/50208575?v=4?s=100\" width=\"100px;\" alt=\"tcudok-jg\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003etcudok-jg\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=tcudok-jg\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/heymartinadams\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/11673745?v=4?s=100\" width=\"100px;\" alt=\"Martin Adams\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMartin Adams\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=heymartinadams\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://gal.js.org\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/191608?v=4?s=100\" width=\"100px;\" alt=\"Gal Dubitski\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eGal Dubitski\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=galmail\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Agalmail\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=galmail\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=galmail\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://twitter.com/osdevisnot\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/802242?v=4?s=100\" width=\"100px;\" alt=\"Abhishek Shende\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAbhishek Shende\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=osdevisnot\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Aosdevisnot\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://fabien.cool\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/1702255?v=4?s=100\" width=\"100px;\" alt=\"fabienheureux\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003efabienheureux\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/pulls?q=is%3Apr+reviewed-by%3Afabienheureux\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://hughboylan.com\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/2158740?v=4?s=100\" width=\"100px;\" alt=\"Hugh Boylan\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eHugh Boylan\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/pulls?q=is%3Apr+reviewed-by%3Ahboylan\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/bmamouri\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/6419173?v=4?s=100\" width=\"100px;\" alt=\"Baqer Mamouri\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eBaqer Mamouri\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=bmamouri\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://www.netnotion.com\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/17315?v=4?s=100\" width=\"100px;\" alt=\"Guillermo Gonzalez \"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eGuillermo Gonzalez \u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=helloguille\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/brookback\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/30257156?v=4?s=100\" width=\"100px;\" alt=\"Johan Brook\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJohan Brook\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=brookback\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Abrookback\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"#maintenance-brookback\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/frikille\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/569278?v=4?s=100\" width=\"100px;\" alt=\"Peter Balazs\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePeter Balazs\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=frikille\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=frikille\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#example-frikille\" title=\"Examples\"\u003e💡\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=frikille\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://panz3r.dev\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/1754457?v=4?s=100\" width=\"100px;\" alt=\"Mattia Panzeri\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMattia Panzeri\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=panz3r\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=panz3r\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/lynxtaa\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/22496946?v=4?s=100\" width=\"100px;\" alt=\"Alex Kondratyuk\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlex Kondratyuk\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=lynxtaa\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=lynxtaa\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=lynxtaa\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Alynxtaa\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/cepelinc\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/25613873?v=4?s=100\" width=\"100px;\" alt=\"Matias Cepeda\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMatias Cepeda\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=cepelinc\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/jackh726\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/31162821?v=4?s=100\" width=\"100px;\" alt=\"Jack Huey\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJack Huey\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/issues?q=author%3Ajackh726\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=jackh726\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=jackh726\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=jackh726\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/zanettin\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/3241476?v=4?s=100\" width=\"100px;\" alt=\"Roman Zanettin\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eRoman Zanettin\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=zanettin\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nearform/graphql-hooks/commits?author=zanettin\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://edge33.github.io\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/5662280?v=4?s=100\" width=\"100px;\" alt=\"Francesco Maida\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eFrancesco Maida\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#maintenance-edge33\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome!\n\n[![banner](https://raw.githubusercontent.com/nearform/.github/refs/heads/master/assets/os-banner-green.svg)](https://www.nearform.com/contact/?utm_source=open-source\u0026utm_medium=banner\u0026utm_campaign=os-project-pages)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnearform%2Fgraphql-hooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnearform%2Fgraphql-hooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnearform%2Fgraphql-hooks/lists"}