120 lines
3.2 KiB
Markdown
120 lines
3.2 KiB
Markdown
---
|
|
tags: [graphql]
|
|
---
|
|
|
|
# Apollo Client
|
|
|
|
Apollo Client is the client-side counterpart to
|
|
[Apollo Server](Apollo_Server.md). We use it for
|
|
managing queries and mutations from the frontend to our Apollo GraphQL server.
|
|
It is specifically designed to work with React.
|
|
|
|
> We will be working with the
|
|
> [schema](Apollo_Server.md#example-schema) we defined
|
|
> when working on the server
|
|
|
|
## Initializing the client
|
|
|
|
We initialise the client and set-up in memory caching to reduce network
|
|
requests:
|
|
|
|
```js
|
|
const client = new ApolloClient({
|
|
uri: "http://localhost:4000",
|
|
cache: new InMemoryCache(),
|
|
});
|
|
```
|
|
|
|
> The `uri` property must match the location of our Apollo server.
|
|
|
|
## Utilising the provider
|
|
|
|
Apollo provides a top level application context that we can wrap our React app
|
|
in. This will provide access to the client object from anywhere within the app,
|
|
eg:
|
|
|
|
```jsx
|
|
ReactDOM.render(
|
|
<ApolloProvider client={client}>
|
|
<GlobalStyles />
|
|
<Pages />
|
|
</ApolloProvider>,
|
|
document.getElementById("root")
|
|
);
|
|
```
|
|
|
|
## Running a query
|
|
|
|
### Queries as entry points
|
|
|
|
From the client point of view, the queries in the schema are _entry points_.
|
|
Although the queries exist in the schema, this alone is not sufficient for them
|
|
to be entry points. Remember a schema is just a specification or contract
|
|
between the frontend and the backend, it is not itself executable code.
|
|
|
|
Therefore, for each query in the schema we must write a frontend implementation.
|
|
We do this with **query constants**. The frontend implementation has a backend
|
|
analogue: the
|
|
[resolver](Apollo_Server.md#implementing-resolvers)
|
|
that is invoked when the frontend issues a query. The schema standardises this
|
|
relationship so that every query on the client must have a corresponding
|
|
resolver on the backend.
|
|
|
|
### Query constants
|
|
|
|
To run a query against our server we must define a query contant first. We use a
|
|
`gql` literal again:
|
|
|
|
```js
|
|
import { gql } from "@apollo/client";
|
|
const TRACKS = gql`
|
|
query GetTracks {
|
|
tracksForHome {
|
|
id
|
|
title
|
|
thumbnail
|
|
length
|
|
modulesCount
|
|
author {
|
|
name
|
|
photo
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
```
|
|
|
|
The convention is to name the query constant in `ALL_CAPS`.
|
|
|
|
> Note that the name of the query on the client doesn't have to match the query
|
|
> type defined in the schema (there is no `GetTracks` in the schema), this is
|
|
> just a client-side designator. However it should reference the schema on the
|
|
> second line (`tracksForHome`).
|
|
|
|
### `useQuery` hook
|
|
|
|
The `useQuery` hook provides a straightforward wrapper for sending queries and
|
|
receiving data back from the server.
|
|
|
|
When a component renders, `useQuery` returns an object from the Apollo Client
|
|
that contains loading, error, and data properties.
|
|
|
|
```jsx
|
|
const { loading, error, data } = useQuery(TRACKS);
|
|
|
|
const Tracks = () => {
|
|
const { loading, error, data } = useQuery(TRACKS);
|
|
|
|
if (loading) return "Loading...";
|
|
|
|
if (error) return `Error! ${error.message}`;
|
|
|
|
return <Layout grid>{JSON.stringify(data)}</Layout>;
|
|
};
|
|
```
|
|
|
|
- We destructure the `loading, error, data` variables that are returned from the
|
|
hook
|
|
- We pass in our query constant as an argument.
|
|
- In the example we just render the serialized data but we could of course pass
|
|
the data as a prop and map through it in an embedded child component.
|