Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@jeremydurnell/react-apollo-hooks

JeremyDurnell55MIT0.4.7TypeScript support: included

Use Apollo Client as React hooks.

readme

react-apollo-hooks

Use Apollo Client as React hooks.

Installation

npm install @jeremydurnell/react-apollo-hooks

Or if using yarn

yarn add @jeremydurnell/react-apollo-hooks

Example

https://codesandbox.io/s/8819w85jn9 is a port of Pupstagram sample app to react-apollo-hooks.

NOTE: This example is outdated and may not work properly. Support for React Suspense was removed in version 0.4.6 of this package.

API

ApolloProvider

Similar to ApolloProvider from react-apollo. Both packages can be used together, if you want to try out using hooks and retain Query, Mutation, Subscription, etc. HOCs from react-apollo without having to rewrite existing components throughout your app.

In order for this package to work, you need to wrap your component tree with ApolloProvider at an appropriate level, encapsulating all components which will use hooks.

Standalone usage

If you would like to use this package standalone, this can be done with:

import React from 'react';
import { render } from 'react-dom';

import { ApolloProvider } from 'react-apollo-hooks';

const client = ... // create Apollo client

const App = () => (
  <ApolloProvider client={client}>
    <MyRootComponent />
  </ApolloProvider>
);

render(<App />, document.getElementById('root'));

Usage with react-apollo

To use with react-apollo's ApolloProvider already present in your project:

import React from 'react';
import { render } from 'react-dom';

import { ApolloProvider } from 'react-apollo';
import { ApolloProvider as ApolloHooksProvider } from 'react-apollo-hooks';

const client = ... // create Apollo client

const App = () => (
  <ApolloProvider client={client}>
    <ApolloHooksProvider client={client}>
      <MyRootComponent />
   </ApolloHooksProvider>
  </ApolloProvider>
);

render(<App />, document.getElementById('root'));

useQuery

import gql from 'graphql-tag';
import { useQuery } from 'react-apollo-hooks';

const GET_DOGS = gql`
  {
    dogs {
      id
      breed
    }
  }
`;

const Dogs = () => {
  const { data, error, loading } = useQuery(GET_DOGS);
  if (loading) {
    return <div>Loading...</div>;
  };
  if (error) {
    return <div>Error! {error.message}</div>;
  };

  return (
    <ul>
      {data.dogs.map(dog => (
        <li key={dog.id}>{dog.breed}</li>
      ))}
    </ul>
  );
};

useMutation

import gql from 'graphql-tag';
import { useMutation } from 'react-apollo-hooks';

const TOGGLE_LIKED_PHOTO = gql`
  mutation toggleLikedPhoto($id: String!) {
    toggleLikedPhoto(id: $id) @client
  }
`;

const DogWithLikes = ({ url, imageId, isLiked }) => {
  const toggleLike = useMutation(TOGGLE_LIKED_PHOTO, {
    variables: { id: imageId },
  });
  return (
    <div>
      <img src={url} />
      <button onClick={toggleLike}>{isLiked ? 'Stop liking' : 'like'}</button>
    </div>
  );
};

You can provide any mutation options as an argument to the useMutation hook or to the function returned by it, e. g.:

function AddTaskForm() {
  const inputRef = useRef();
  const addTask = useMutation(ADD_TASK_MUTATION, {
    update: (proxy, mutationResult) => {
      /* your custom update logic */
    },
    variables: {
      text: inputRef.current.value,
    },
  });

  return (
    <form>
      <input ref={inputRef} />
      <button onClick={addTask}>Add task</button>
    </form>
  );
}

Or:

function TasksWithMutation() {
  const toggleTask = useMutation(TOGGLE_TASK_MUTATION);

  return (
    <TaskList
      onChange={task => toggleTask({ variables: { taskId: task.id } })}
      tasks={data.tasks}
    />
  );
}

useSubscription

If you are just interested in the last subscription value sent by the server (e. g. a global indicator showing how many new messages you have in an instant messenger app) you can use useSubscription hook in this form:

const NEW_MESSAGES_COUNT_CHANGED_SUBSCRIPTION = gql`
  subscription onNewMessagesCountChanged($repoFullName: String!) {
    newMessagesCount
  }
`;

const NewMessagesIndicator = () => {
  const { data, error, loading } = useSubscription(
    NEW_MESSAGES_COUNT_CHANGED_SUBSCRIPTION
  );

  if (loading) {
    return <div>Loading...</div>;
  };

  if (error) {
    return <div>Error! {error.message}</div>;
  };

  return <div>{data.newMessagesCount} new messages</div>;
}

For more advanced use cases, e. g. when you'd like to show a notification to the user or modify the Apollo cache (e. g. you'd like to show a new comment on a blog post page for a user visiting it just after it was created) you can use the onSubscriptionData callback:

const { data, error, loading } = useSubscription(MY_SUBSCRIPTION, {
  variables: {
    // ...
  },
  onSubscriptionData: ({ client, subscriptionData }) => {
    // Optional callback which provides you access to the new subscription
    // data and the Apollo client. You can use methods of the client to update
    // the Apollo cache:
    // https://www.apollographql.com/docs/react/advanced/caching.html#direct
  }
  // ... rest options
});

In some cases you might want to subscribe only after you have all the information available, eg. only when user has selected necessary filters. Since hooks cannot be used conditionally, it would lead to unnecessary complicated patterns.

Instead, you can use the skip option which turns the subsciption dormant until toggled again. It will also unsubscribe if there was any previous subscription active and throw away previous result.

useApolloClient

const MyComponent = () => {
  const client = useApolloClient();
  // now you have access to the Apollo client
};

Testing

An example showing how to test components using react-apollo-hooks: https://github.com/trojanowski/react-apollo-hooks-sample-test

Server-side rendering

react-apollo-hooks supports server-side rendering with the getMarkupFromTree function. Example usage:

import express from 'express';
import { ApolloProvider, getMarkupFromTree } from 'react-apollo-hooks';
import { renderToString } from 'react-dom/server';

const HELLO_QUERY = gql`
  query HelloQuery {
    hello
  }
`;

function Hello() {
  const { data } = useQuery(HELLO_QUERY);

  return <p>{data.message}</p>;
}

const app = express();

app.get('/', async (req, res) => {
  const client = createYourApolloClient();
  const renderedHtml = await getMarkupFromTree({
    renderFunction: renderToString,
    tree: (
      <ApolloProvider client={client}>
        <Hello />
      </ApolloProvider>
    ),
  });
  res.send(renderedHtml);
});

changelog

Change Log

All notable changes to this project will be documented in this file. See standard-version for commit guidelines.

0.4.5 (2019-04-06)

Performance Improvements

0.4.4 (2019-03-25)

Bug Fixes

  • when there is an error the query returns with the previous data instead of empty data (#100) (583da31)

0.4.3 (2019-03-01)

Features

  • useQuery, useMutation: accept client option (#95) (0ba17aa)

0.4.2 (2019-02-27)

Features

  • useSubscription: add skip option (#98) (8670f7f)

0.4.1 (2019-02-22)

Features

0.4.0 (2019-02-13)

Bug Fixes

Chores

  • update React peer dependency to ^16.8.0 (#78) (56abacc)

Features

  • getMarkupFromTree: add onBeforeRender handler (#64) (ba2af83)
  • useQuery: change default value for the suspend option to false (#80) (8e34e01)
  • useQuery: combine GraphQL errors in single ApolloError (#58) (18afba5)
  • useQuery: forward networkStatus for queries not using suspense (fb22d06)

BREAKING CHANGES

  • useQuery: The default for the suspend option of useQuery is changed to false, and that hook no longer uses suspense by default. Suspense for data fetching is not recommended yet for production code. Please look at the issue #69 for details.
  • minimum supported (and tested) version of React is now 16.8.0
  • useQuery: if there are GraphQL errors in the response, you'll also have error property in the object returned by useQuery. It may be breaking for you if you use the presence of it to differentiate between network and GraphQL errors.

0.3.1 (2019-01-25)

Bug Fixes

  • notifyOnNetworkStatusChange defaults to false (#61) (4da7d2d), closes #59

0.3.0 (2019-01-16)

Bug Fixes

  • update React peer dependency (51b3435)

Code Refactoring

Features

  • useQuery: implement skip (#42) (873e7de)
  • useQuery: use Apollo client state as the main source of truth (#47) (5ed243d)
  • implement SSR (#44) (664edc2)

BREAKING CHANGES

  • minimum supported (and tested) version of React is now 16.8.0-alpha.1
  • useApolloClient throws if the client is not available in the context instead of returning null

0.2.1 (2018-11-30)

Bug Fixes

  • add graphql to peer dependencies (9488383)

0.2.0 (2018-11-30)

Bug Fixes

  • cache queries for not-mounted yet components. It fixes problems with infinite loops after error occurred. (246208c), closes #23
  • remove no longer needed warning dependency (0c4459b)
  • update React peer dependency (768d851)

Features

  • remove deprecated methods (a601691)

BREAKING CHANGES

  • minimum supported (and tested) version of React is now 16.7.0-alpha.2
  • useApolloQuery and useApolloMutation are removed. Please use useQuery and useMutation instead.

0.1.8 (2018-11-29)

Bug Fixes

  • typescript: parametrize update option of useMutation hook (f8d6c26)

0.1.7 (2018-11-27)

Features

  • add more ObservableQuery functions to useQuery (b0a3923), closes #24

0.1.6 (2018-11-13)

Features

  • typescript: add notifyOnNetworkStatusChange and pollInterval to useQuery options in TypeScript definitions (f2db5b3), closes #18

0.1.5 (2018-11-10)

Bug Fixes

  • typescript: make suspend option of useQuery hook optional (7e776a6)

0.1.4 (2018-11-10)

Features

  • allow to use useQuery hook without suspense (db119e5)

0.1.3 (2018-11-08)

Features

  • add useQuery and useMutation hooks; deprecate useApolloQuery and useApolloMutation (e769f94), closes #6 #9

0.1.2 (2018-11-07)

Features

  • ts: allow to specify a TypeScript result type of mutations (7ff3647), closes #10