Skip to content
This repository has been archived by the owner on Apr 19, 2023. It is now read-only.

A render component for easy querying and mutating of your GraphQL API.

License

Notifications You must be signed in to change notification settings

department-stockholm/apollo-component

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Apollo Component

npm version

A render component for easy querying and mutating of your GraphQL API.

Install

npm install @department/apollo-component

Examples

Here is an example of fetching and rendering the data of an imaginary Order.

import { gql } from "graphql-tag"
import { Query } from "@department/apollo-component"
import SingleOrder, { LoadingOrder } from "components/SingleOrder"
import { GenericError, NotFound } from "components/Errors"

const ShowOrderQuery = gql`
  query ShowOrder($id: ID!) {
    Order(id: $id) {
      ...SingleOrder
    }
  }
  ${SingleOrder.fragments.SingleOrder}
`;

const Show = ({ id }) => (
  <Query gql={ShowOrderQuery} variables={{id}}>
    {({ data: { Order }, loading, error, refetch }) =>
      loading ? (
        <LoadingOrder />
      ) : error ? (
        <GenericError error={error} />
      ) : (
        <SingleOrder {...Order} update={refetch} />
      )}
  </Query>
));

And another example using <Mutate/> and fail-props to raise any errors to the nearest React 16+ Error Boundary:

import { gql } from "graphql-tag";
import { Mutate, Query } from "@department/apollo-component";
import { Exception } from "components/Exception";

const IncrementMutation = gql`
  mutation IncrementMutation($num: Int!) {
    incr(num: $num)
  }
`;

const ShowCountQuery = gql`
  query ShowCount {
    count
  }
`;

const IncrementView = ({ id }) => (
  <Exception>
    <Query gql={ShowCount} wait fail>
      {({ data: { count } }) => <div>Current count: {count}</div>}
    </Query>
    <Mutate gql={IncrementMutation} refetchQueries={["ShowCount"]} fail>
      {incr => (
        <form onSubmit={e => incr({ num: e.currentTarget.num.valueAsNumber })}>
          <input type="number" name="num" value={1} step={1} />
          <button>+</button>
        </form>
      )}
    </Mutate>
  </Exception>
);

API

<Query />

Available Props:

  • gql
  • wait
  • lazy
  • fail
  • skip
  • variables

Arguments in render callback

  • QueryResults
    • data the loaded data or an empty object
    • loading true while loading (unless the wait-prop was set)
    • skipped true if the request was skipped (using the skip-prop)
    • error Error object if there was any error (unless the fail-props was set)
    • refetch(variables) call this function rerun query with, optionally, new variables
    • fetchMore(opts) call this function to fetch more (read about the opts)
Example:
({ data: { stuff }, loading }) => <div>{loading ? "loading..." : stuff}</div>;

<Mutate />

Available Props:

  • gql
  • refetchQueries
  • optimisticResponse
  • update

Arguments in render callback

  • Mutate(variables) call this function to trigger the mutation
  • QueryResults (like for Query but without skipped)
    • data
    • loading
    • error
    • refetch
    • fetchMore
Example:
(mutate, { data: { stuff }, loading }) => (
  <button onClick={() => mutate()} disabled={loading}>
    {loading ? "loading..." : stuff}
  </button>
);

renderState(client, component, options)

For server side rendering renderState() may be used. It uses a query queue in the React Context which is populated by <Query/> in its componentWillMount() lifecycle method using a naïve component renderer.

It will by default render the tree repeatedly until all queries, without the lazy-prop has been completed but the maximum "depth" may be adjusted with the maxDepth option.

Arguments

  • client an instance of ApolloClient
  • component the root component, will be wrapped by a <Provider /> with a queue
  • RenderStateOptions
    • maxDepth number of attempts to render the tree, defaults to Infinity (until no more queries are to be found)

Example

An example which could be used to server side render.

Note how the <Provider/> is not needed in renderState(), it's because it wraps the component with a special one.

function renderHTML() {
  return renderState(client, <App />, { maxDepth: 1 })
    .then(() =>
      ReactDOM.renderToString(
        <Provider client={client}>
          <App />
        </Provider>
      )
    )
    .catch(err => {
      // you can let the error throw here
      // or ignore it and let the client side
      // handle it inline
      console.error("failed to render state:", err);
      return renderErrorPage(err);
    });
}