Jeff Lowery

@jefflowery

Giving React + GraphQL a Lift with Apollo-Boost

If you’re using GraphQL in your projects you’re sure to have come across the Apollo and their GraphQL-enabled tools.

One of the toolsets Apollo has introduced is Apollo-Boost (which I’ll refer to simply as Boost from here on). Boost allows for minimal Apollo Client configuration and boilerplate in you applications. Apollo Client itself is a wrapper class designed to simplify interaction with GraphQL servers (and, as we shall see, client-side GraphQL as well).

They also have tool support for the React framework, among others. While the Client is framework-independent, the react-apollo library has components that integrate seamlessly with Apollo Client.

Installation

To quickly get up and running with a new react-apollo client, I recommend using create-react-app:

npx create-react-app create_react_app

Note that it is npx, not npm; create_react_app is the name I chose for the new project. The resulting package.json file will contain the following:

{
"name": "create_react_app",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.5.2",
"react-dom": "^16.5.2",
"react-scripts": "1.1.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}

You’ll notice that there are several build scripts provided, and react-scripts is used as the application launcher. The react-scripts launcher provides a curated list of dependencies with minimal configuration. You can read about what is provided here. When npm run start is executed, it will launch a hot React server (one that relaunches when detecting code changes) and will automatically load a sample application page in your browser.

There are three additional packages (already mentioned) that need to be installed before continuing:

npm install --save apollo-boost react-apollo graphql

Building the App

The primary tool provided by Boost is the ApolloClient class. This provides query, mutation, and subscription methods that simplify client-GraphQL interaction by means of Promises.

The first step is to configure an ApolloClient instance. I’ll use the GraphQL server settings provided in the Apollo Client installation instructions.

import ApolloClient from "apollo-boost";

const client = new ApolloClient({
uri: "https://w5xlvm3vzz.lp.gql.zone/graphql"
});

The server was built using Apollo Launchpad (another GraphQL tool you should have in your belt), and you can access it online here. Note that as of this writing, the Query shown in the Launchpad is wrong, and should be something like:

query rates($currency: String!) {
rates(currency: $currency) {
currency
rate
name
}
}

With the client set up, next plug in an ApolloProvider component into the application:

(I’ve cleaned up the syntax a bit from the original generated application.)

The ApolloProvider is the connecting component between the React application and the GraphQL client. From within the provider, we can add Query and Mutation components in the application which operate against a context. You can think of the context as the state of the application, but one that is accessed via GraphQL scripts.

Using Queries

The Query component takes a GraphQL query string as a property. That query string is executed when the component is rendered, invoking a function that takes loading state, errors (if any) and a data result as parameters. What usually happens (on a good day) is that once loading is false (query data is done loading), and no errors are returned, then the data properties are passed down to child components.

Taking that query shown earlier, we can create a simple display:

And then, back in the main application:

import ExchangeRates from './ExchangeRates'
const client = new ApolloClient({
uri: "https://w5xlvm3vzz.lp.gql.zone/graphql"
});
const App = () => (
<ApolloProvider client={client}>
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<ExchangeRates/>
</div>
</ApolloProvider>
)

You’ll notice that ExchangeRates makes its own Query, so that the component is entirely self-contained.

The resulting page is no beauty, but it is accurate:

Partial list of currency exchange rates relative to the dollar (USD)

Default Values and Client Context

Next is to make better use of that screen real estate at the top where the React logo is shown, replacing it with a currency input so that the user doesn’t have to scroll through a large list of currency abbreviations to find the one she’s interested in.

Setting up default values

Adding a default value (or values) to start the application with is a pretty simple modification to the ApolloClient configuration shown earlier:

const client = new ApolloClient({
uri: "https://w5xlvm3vzz.lp.gql.zone/graphql",
clientState: {
defaults: {
currencyOfInterest: 'USD',
}
}

})

The currencyOfInterest will be stored locally, on the client. We inform the query of the location through the @client directive. I change the original component layout slightly so that the original query results from the server are passed down to the ExchangeSelector via props.

const ExchangeRates = (client) => (
<Query
query={gql`
{
rates(currency: "USD") {
currency
rate
name
}
}
`}
>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (<div>
<header className="App-header">
<ExchangeSelector data={data}/>
</header>
<ExchangeList data={data} />;
</div>)
}}
</Query>
);

Here’s a look at the new React ExchangeSelector component:

The @client designation one line 6 tells ApolloClient that the value can be found in the local cache. This value can be accessed and written to just as if it resided on the server, through Query and Mutation operations. However, since this is locally stored, it is often more convenient to update the client cache directly, using client.writeData() as shown on line 21.

The ExchangeSelector gets rates from it’s parent container and all three input elements are updated when the input for currencyOfInterest is changes (lines 20–21). The onChange handler writes directly to the client’s cache, which will trigger a re-render of the ExchangeSelector itself.

Wrapping it Up

Complete code for this example can be found here. The README.md goes into detail about create-react-app (I didn’t write it, it did).

More by Jeff Lowery

Topics of interest

More Related Stories