π£ Minimal hooks-first GraphQL client.
- π₯ 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
npm install graphql-hooks
or
yarn add graphql-hooks
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>
);
}- API
- Guides
Usage:
import { GraphQLClient } from 'graphql-hooks';
const client = new GraphQLClient(config);config: Object containing configuration properties
url(Required): The url to your GraphQL serverssrMode: Boolean - set totruewhen using on the server for server-side rendering; defaults tofalsecache: 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 globalfetchAPIfetchOptions: See MDN for info on what options can be passedheaders: Object, e.g.{ 'My-Header': 'hello' }logErrors: Boolean - defaults totrueonError({ operation, result }): Custom error handleroperation: Object withquery,variablesandoperationNameresult: Object containingerror,data,fetchError,httpErrorandgraphqlErrors
client.setHeader(key, value): Updatesclient.headersadding the new header to the existing headersclient.setHeaders(headers): Replacesclient.headersclient.logErrorResult({ operation, result }): Default error logger; useful if you'd like to use it inside your customonErrorhandlerrequest(operation, options): Make a request to your GraphQL server; returning a Promiseoperation: Object withquery,variablesandoperationName
options.fetchOptionsOverrides: Object containing additional fetch options to be added to the default ones passed tonew GraphQLClient(config)
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);
}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 stringoptions: 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.useCache: Boolean - defaults totrue; cache the query resultskipCache: Boolean - defaults tofalse; Iftrueit will by-pass the cache and fetch, but the result will then be cached for subsequent calls. Note therefetchfunction will do this automaticallyssr: Boolean - defaults totrue. Set tofalseif you wish to skip this query during SSRfetchOptionsOverrides: Object - Specific overrides for this query. See MDN for info on what options can be passed
const { loading, error, data, refetch, cacheHit, ...errors } = useQuery(QUERY);loading: Boolean -trueif the query is in flighterror: Boolean -trueiffetchErrororhttpErrororgraphQLErrorshas been setdata: Object - the result of your GraphQL queryrefetch: Function - useful when refetching the same query after a mutation; NOTE this presetsskipCache=truecacheHit: Boolean -trueif the query result came from the cache, useful for debuggingfetchError: Object - Set if an error occured during thefetchcallhttpError: Object - Set if an error response was returned from the servergraphQLErrors: Array - Populated if any errors occured whilst resolving the query
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>
);
}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
See graphql-hooks-ssr for an in depth guide.
Coming soon!
Coming soon!
Coming soon!