Skip to content

nearform/graphql-hooks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

37 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

graphql-hooks

CircleCI Coverage Status npm version

🎣 Minimal hooks-first GraphQL client.

Features

  • πŸ₯‡ First-class hooks API
  • βš–οΈ Tiny bundle: only 3.7kB (1.4 gzipped)
  • πŸ“„ Full SSR support: see graphql-hooks-ssr
  • πŸ”Œ Plugin Caching: see graphql-hooks-memcache
  • πŸ”₯ No more render props hell
  • ⏳ Handle loading and error states with ease

Install

npm install graphql-hooks

or

yarn add graphql-hooks

Quick Start

First 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>
  );
}

Table of Contents

API

GraphQLClient

Usage:

import { GraphQLClient } from 'graphql-hooks';
const client = new GraphQLClient(config);

config: Object containing configuration properties

  • url (Required): The url to your GraphQL server
  • ssrMode: Boolean - set to true when using on the server for server-side rendering; defaults to false
  • cache: Object with the following methods:
    • cache.get(key)
    • cache.set(key, data)
    • cache.delete(key)
    • cache.clear()
    • cache.keys()
    • getInitialState()
    • See graphql-hooks-memcache as a reference implementation
  • fetch(url, options): Fetch implementation - defaults to the global fetch API
  • fetchOptions: See MDN for info on what options can be passed
  • headers: Object, e.g. { 'My-Header': 'hello' }
  • logErrors: Boolean - defaults to true
  • onError({ operation, result }): Custom error handler
    • operation: Object with query, variables and operationName
    • result: Object containing error, data, fetchError, httpError and graphqlErrors

client methods

  • client.setHeader(key, value): Updates client.headers adding the new header to the existing headers
  • client.setHeaders(headers): Replaces client.headers
  • client.logErrorResult({ operation, result }): Default error logger; useful if you'd like to use it inside your custom onError handler
  • request(operation, options): Make a request to your GraphQL server; returning a Promise
    • operation: Object with query, variables and operationName
  • options.fetchOptionsOverrides: Object containing additional fetch options to be added to the default ones passed to new GraphQLClient(config)

ClientContext

ClientContext is the result of React.createContext() - meaning it can be used directly with React's new context API:

Example:

import { ClientContext } from 'graphql-hooks';
<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);
}

useQuery

Usage:

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 <div>{data.thing}</div>;
}

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
  • options: Object with the following optional properties
    • variables: Object e.g. { limit: 10 }
    • operationName: If your query has multiple operations, pass the name of the operation you wish to execute.
    • useCache: Boolean - defaults to true; cache the query result
    • 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
    • ssr: Boolean - defaults to true. Set to false if you wish to skip this query during SSR
    • fetchOptionsOverrides: Object - Specific overrides for this query. See MDN for info on what options can be passed

useQuery return value

const { loading, error, data, refetch, cacheHit, ...errors } = useQuery(QUERY);
  • loading: Boolean - true if the query is in flight
  • error: Boolean - true if fetchError or httpError or graphQLErrors has been set
  • data: Object - the result of your GraphQL query
  • refetch: Function - useful when refetching the same query after a mutation; NOTE this presets skipCache=true
  • cacheHit: Boolean - true if the query result came from the cache, useful for debugging
  • fetchError: Object - Set if an error occured during the fetch call
  • httpError: Object - Set if an error response was returned from the server
  • graphQLErrors: Array - Populated if any errors occured whilst resolving the query

useManualQuery

Use this when you don't want a query to automactially 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 (
    <div>
      <button onClick={fetchUser}>Get User!</button>
      {error && <div>Failed to fetch user<div>}
      {loading && <div>Loading...</div>}
      {data && <div>Hello ${data.user.name}</div>}
    </div>
  )
}

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:

import { useManualQuery } from 'graphql-hooks';

function MyComponent(props) {
  const [fetchUser] = useManualQuery(GET_USER_QUERY);

  const fetchUserThenSomething = async () => {
    const user = await fetchUser({
      variables: { id: props.userId }
    });
    return somethingElse();
  };

  return (
    <div>
      <button onClick={fetchUserThenSomething}>Get User!</button>
    </div>
  );
}

useMutation

Mutations unlike Queries are not cached.

Usage:

const [mutationFn, state] = useMutation(mutation, [options]);

Example:

import { useMutation } from 'graphql-hooks';

const UPDATE_USER_MUTATION = `mutation UpdateUser(id: String!, name: String!) {
  updateUser(id: $id, name: $name) {
    name
  }
}`;

function MyComponent({ id, name }) {
  const [updateUser] = useMutation(UPDATE_USER_MUTATION);
  const [newName, setNewName] = useState(name);

  return (
    <div>
      <input
        type="text"
        value={newName}
        onChange={e => setNewName(e.target.value)}
      />
      <button
        onClick={() => updateUser({ variables: { id, name: newName } })}
      />
    </div>
  );
}

The options object that can be passed either to useMutation(mutation, options) or mutationFn(options) can be set with the following properties:

  • variables: Object e.g. { limit: 10 }
  • operationName: If your query has multiple operations, pass the name of the operation you wish to execute.
  • fetchOptionsOverrides: Object - Specific overrides for this query. See MDN for info on what options can be passed

Guides

SSR

See graphql-hooks-ssr for an in depth guide.

Authentication

Coming soon!

Fragments

Coming soon!

Migrating from Apollo

Coming soon!